package com.code.service.impl;

import com.code.AZPlan.client.AZPlanStaticIncomeClient;
import com.code.AZPlan.model.bo.*;
import com.code.AZPlan.model.po.*;
import com.code.commons.constants.ServerConstants;
import com.code.commons.enums.CacheKeyEnum;
import com.code.commons.enums.ResultCode;
import com.code.commons.exceptions.BusinessException;
import com.code.commons.util.*;
import com.code.commons.web.constants.HeaderConstants;
import com.code.config.redis.RedisHandler;
import com.code.helper.PasswordHelper;
import com.code.manager.ExchangeHouseManager;
import com.code.manager.HttpManager;
import com.code.mapper.XTMapper;
import com.code.model.bo.wallet.DepositTran;
import com.code.model.bo.wallet.WithdrawTran;
import com.code.model.vo.az.FastNewsResponseVo;
import com.code.service.AZPlanStaticIncomeService;
import com.code.user.client.LoginCredentialClient;
import com.code.user.client.UserClient;
import com.code.user.model.bo.LoginUser;
import com.code.user.model.po.*;
import com.code.user.token.helper.LoginTokenHelper;
import com.code.user.token.service.LoginTokenService;
import com.google.common.cache.Cache;
import com.google.common.cache.CacheBuilder;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;
import org.springframework.web.client.RestTemplate;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * AZ计划静态收益业务聚合服务层
 *
 * @author tangyifei
 */
@Service
@Slf4j
public class AZPlanStaticIncomeServiceImpl implements AZPlanStaticIncomeService {

    private static final String EXCHANGE_USDT_RATIO = "1";

    @Resource
    private AZPlanStaticIncomeClient azPlanStaticIncomeClient;

    @Resource
    private UserClient userClient;

    @Resource
    private LoginCredentialClient loginCredentialClient;

    @Resource
    HttpManager httpManager;

    @Resource
    XTMapper xtMapper;

    @Resource
    private LoginTokenService loginTokenService;

    @Resource
    ExchangeHouseManager exchangeHouseManager;

    @Resource
    private RedisHandler redisHandler;

    @Value("${withdraw.min.btc}")
    private BigDecimal btcMinWithdrawAmount;

    @Value("${withdraw.min.xwc}")
    private BigDecimal xwcMinWithdrawAmount;

    @Value("${withdraw.min.usdt}")
    private BigDecimal usdtMinWithdrawAmount;

    @Value("${withdraw.fee.btc}")
    private BigDecimal btcMinWithdrawFeeRatio;

    @Value("${withdraw.fee.xwc}")
    private BigDecimal xwcMinWithdrawFeeRatio;

    @Value("${withdraw.fee.usdt}")
    private BigDecimal usdtMinWithdrawFeeRatio;

    @Value("${dapp.defaultUser}")
    private String defaultUserPhone;

    @Value("${news.bitwires.channel}")
    private String newsChannel;

    @Value("${news.bitwires.key}")
    private String newsKey;

    @Value("${news.bitwires.url}")
    private String newsUrl;

    /**
     * 最新资讯本地连接,1分钟请求一次
     **/
    private static final Cache<String, FastNewsResponseVo> NEWS_LOCAL_CACHE = CacheBuilder.newBuilder()
            .expireAfterWrite(5, TimeUnit.SECONDS)
            .build();

    /**
     * 刷新内存树
     */
    @Override
    public void reloadAccountTree() {
        azPlanStaticIncomeClient.reloadAccountTree();
    }

    /**
     * 资金划转
     *
     * @param moneyTransferRecord 资金划转记录实体
     * @return 资金划转记录实体
     */
    @Override
    public MoneyTransferRecord moneyTransfer(MoneyTransferRecord moneyTransferRecord) {
        Assert.notNull(moneyTransferRecord, "moneyTransferRecord is not null");
        log.info("请求参数：【{}】", moneyTransferRecord.toString());
        BigDecimal amount = moneyTransferRecord.getAmount();
        //资金划转分为两种情况，分别是从钱包划转到AZ计划，从AZ计划划转到钱包
        int transferType = moneyTransferRecord.getTransferType();
        String coinType = moneyTransferRecord.getCoinType();
        LoginUser loginUser = LoginTokenHelper.getLoginUserFromRequest();
        String userId = moneyTransferRecord.getUserId();
        String tranPwd = moneyTransferRecord.getTranPwd();
        if (null != loginUser && userId.equals(loginUser.getId())) {
            if (amount.compareTo(BigDecimal.ZERO) <= 0) {
                throw new BusinessException(ResultCode.TRANSFER_AMOUNT_ERROR);
            }
            //验证交易密码是否正确
            LoginCredential loginCredentialForDB = loginCredentialClient.getUserLoginCredential(userId);
            if (null != loginCredentialForDB) {
                String tranPwdForDB = loginCredentialForDB.getTranPwd();
                String salt = loginCredentialForDB.getRandomSalt();
                tranPwd = PasswordHelper.encodeBySalt(tranPwd, salt);
                if (StringUtil.isEmpty(tranPwdForDB) || !tranPwd.equals(tranPwdForDB)) {
                    throw new BusinessException(ResultCode.USER_TRAN_PWD_ERROR);
                }
            } else {
                throw new BusinessException(ResultCode.USER_LOGIN_CRE_IS_NOT_NULL);
            }
            //从钱包划转到AZ计划
            if (transferType == 1) {
                //校验用户余额是否充足
                UserCoinBalance userCoinBalance = userClient.getUserCoinBalance(userId, coinType, null);
                if (null != userCoinBalance) {
                    //BigDecimal coinBalance = httpManager.getCoinBalance(coinType, coinAddress);
                    BigDecimal coinBalance = userCoinBalance.getCoinBalance();
                    if (null == coinBalance || coinBalance.compareTo(BigDecimal.ZERO) <= 0 || coinBalance.compareTo(amount) < 0) {
                        throw new BusinessException(ResultCode.USER_BALANCE_ERROR);
                    }
                    //进行资金划转
                    return azPlanStaticIncomeClient.moneyTransfer(moneyTransferRecord);
                } else {
                    throw new BusinessException(ResultCode.USER_COIN_BALANCE_IS_NOT_NULL);
                }

            }
            //从AZ计划划转到钱包
            if (transferType == 2) {
                AZPlanWallet azPlanWallet = azPlanStaticIncomeClient.getAZPlanWallet(userId, coinType);
                BigDecimal azWalletBalance = azPlanWallet.getAmount();
//                //获取某一个币种总的兑换数量
//                BigDecimal totalExchangeAmount = azPlanStaticIncomeClient.getTotalExchangeAmount(userId, coinType);
//                //获取某一个币种从AZ计划划转到钱包的总额度
//                BigDecimal totalMoneyTransferAmount = azPlanStaticIncomeClient.getTotalMoneyTransferAmount(userId, coinType, transferType);
//                //获取还可以划转的相关币种数量
//                BigDecimal remainMoneyTransferAmount = BigDecimal.ZERO;
//                if (null != totalExchangeAmount && null != totalMoneyTransferAmount) {
//                    remainMoneyTransferAmount = BigDecimalUtils.subtract(String.valueOf(totalExchangeAmount), String.valueOf(totalMoneyTransferAmount));
//                }
                if (azWalletBalance.compareTo(BigDecimal.ZERO) <= 0 || azWalletBalance.compareTo(amount) < 0) {
                    throw new BusinessException(ResultCode.USER_BALANCE_ERROR);
                }
                //进行资金划转
                return azPlanStaticIncomeClient.moneyTransfer(moneyTransferRecord);
            }
            return moneyTransferRecord;
        } else {
            throw new BusinessException(ResultCode.USER_NOT_LOGGED_IN);
        }
    }

    /**
     * 入金
     *
     * @param entryMoneyBO 入金业务对象
     * @return 登陆的用户信息
     */
    @Override
    public EntryMoneyBO entryMoney(EntryMoneyBO entryMoneyBO) throws Exception {
        Assert.notNull(entryMoneyBO, "entryMoneyBO is not null");
        String userId = entryMoneyBO.getUserId();
        LoginUser loginUser = LoginTokenHelper.getLoginUserFromRequest();
        if (null != loginUser && userId.equals(loginUser.getId())) {
            //验证交易密码是否正确
            LoginCredential loginCredentialForDB = loginCredentialClient.getUserLoginCredential(userId);
            String tranPwd = entryMoneyBO.getTranPwd();
            if (null != loginCredentialForDB) {
                String tranPwdForDB = loginCredentialForDB.getTranPwd();
                String salt = loginCredentialForDB.getRandomSalt();
                tranPwd = PasswordHelper.encodeBySalt(tranPwd, salt);
                if (StringUtil.isEmpty(tranPwdForDB) || !tranPwd.equals(tranPwdForDB)) {
                    throw new BusinessException(ResultCode.USER_TRAN_PWD_ERROR);
                }
            } else {
                throw new BusinessException(ResultCode.USER_LOGIN_CRE_IS_NOT_NULL);
            }
            //设置用户手机号，方便内存树打日志
            entryMoneyBO.setPhone(loginUser.getPhone());
            Integer entryMoneyChannelType = entryMoneyBO.getEntryMoneyChannelType();
            //如果为通道1，必须是1000的usdt额度
            log.info("通道：{}", entryMoneyChannelType);
            if (entryMoneyChannelType == 1) {
                String entryOtherCoinType = entryMoneyBO.getEntryOtherCoinType();
                if (ServerConstants.XWC.equalsIgnoreCase(entryOtherCoinType)) {
                    //如果用户之前入过金，那么必须等到之前入金的2000USD释放完才能入金
                    AZPlanBalance azPlanBalance = azPlanStaticIncomeClient.getAZPlanBalanceByUserId(userId);
                    BigDecimal orePool = azPlanBalance.getOrePool();
                    if (orePool.compareTo(BigDecimal.ZERO) > 0) {
                        throw new BusinessException(ResultCode.USER_CANNOT_ENTRY_MONEY);
                    }
                    String xwcExchangeUSDRatio = xtMapper.getXTExchangeRate(ServerConstants.XWC_USDT).getExchangeRate();
                    //获取USD按照兑换比例兑换的XWC的价格
                    BigDecimal xwcExchangeUSDAmount = BigDecimal.ZERO;
                    if (StringUtil.isNotEmpty(xwcExchangeUSDRatio)) {
                        xwcExchangeUSDAmount = BigDecimalUtils.divide(ServerConstants.ONE_CHANNEL_USDT_LOWEST_AMOUNT, xwcExchangeUSDRatio);
                    }
                    //校验用户针对某个币种划转的余额是否充足
                    checkUserBalance(userId, entryOtherCoinType, xwcExchangeUSDAmount);
                    entryMoneyBO.setXwcExchangeUSDAmount(xwcExchangeUSDAmount);
                    //入金
                    EntryMoneyBO entryMoneyBOResult = azPlanStaticIncomeClient.entryMoney(entryMoneyBO);
                    //更新推荐人的token中的VIP信息
//                    List<UserVipBO> userVipBOS = entryMoneyBOResult.getUserVipBOS();
//                    if (CollectionUtil.isNotEmpty(userVipBOS)) {
//                        List<UserToken> userTokens = userClient.getTokenList(userVipBOS);
//                        if (CollectionUtil.isNotEmpty(userTokens)) {
//                            //更新缓存中推荐人的token信息
//                            LoginToken loginToken;
//                            LoginUser loginUserForReq;
//                            String userVip;
//                            String recommendId;
//                            for (UserVipBO userVipBO : userVipBOS) {
//                                userVip = userVipBO.getUserVipLevel();
//                                recommendId = userVipBO.getRecommendId();
//                                for (UserToken userToken : userTokens) {
//                                    if (recommendId.equals(userToken.getRecommendId())) {
//                                        loginToken = loginTokenService.getById(userToken.getTokenId());
//                                        if (null != loginToken) {
//                                            loginUserForReq = loginToken.getLoginUser();
//                                            if (null != loginUserForReq) {
//                                                loginUserForReq.setUserLevel(userVip);
//                                                //更新token里面用户的信息(修改昵称、头像、用户等级)
//                                                loginToken.setLoginUser(loginUserForReq);
//                                                //生成新的token
//                                                loginTokenService.add(loginToken);
//                                            }
//                                        }
//                                        break;
//                                    }
//                                }
//
//                            }
//
//                        }
//
//                    }
                    Integer entryMoneyFailureFlag = entryMoneyBOResult.getEntryMoneyFailureFlag();
                    if (null != entryMoneyFailureFlag && entryMoneyFailureFlag == 1) {
                        throw new BusinessException(ResultCode.ENTRY_MONEY_ERROR);
                    }
                    return entryMoneyBOResult;
                }

            }
            //如果为通道2，必须是3000的usdt额度并享受2.4倍放大额度，即可获得7200USD账户额度
            if (entryMoneyChannelType == 2) {
                String entryOtherCoinType = entryMoneyBO.getEntryOtherCoinType();
                if (ServerConstants.XWC.equalsIgnoreCase(entryOtherCoinType)) {
                    //如果用户之前入过金，那么必须等到之前入金的USD释放完才能入金
                    AZPlanBalance azPlanBalance = azPlanStaticIncomeClient.getAZPlanBalanceByUserId(userId);
                    BigDecimal orePool = azPlanBalance.getOrePool();
                    if (orePool.compareTo(BigDecimal.ZERO) > 0) {
                        throw new BusinessException(ResultCode.USER_CANNOT_ENTRY_MONEY);
                    }
                    String xwcExchangeUSDRatio = xtMapper.getXTExchangeRate(ServerConstants.XWC_USDT).getExchangeRate();
                    //获取USD按照兑换比例兑换的XWC的价格
                    BigDecimal xwcExchangeUSDAmount = BigDecimal.ZERO;
                    if (StringUtil.isNotEmpty(xwcExchangeUSDRatio)) {
                        xwcExchangeUSDAmount = BigDecimalUtils.divide(ServerConstants.TWO_CHANNEL_USDT_LOWEST_AMOUNT, String.valueOf(xwcExchangeUSDRatio));
                    }
                    checkUserBalance(userId, entryOtherCoinType, xwcExchangeUSDAmount);
                    entryMoneyBO.setXwcExchangeUSDAmount(xwcExchangeUSDAmount);
                    //入金
                    EntryMoneyBO entryMoneyBOResult = azPlanStaticIncomeClient.entryMoney(entryMoneyBO);
                    //更新推荐人的token中的VIP信息
//                    List<UserVipBO> userVipBOS = entryMoneyBOResult.getUserVipBOS();
//                    if (CollectionUtil.isNotEmpty(userVipBOS)) {
//                        List<UserToken> userTokens = userClient.getTokenList(userVipBOS);
//                        if (CollectionUtil.isNotEmpty(userTokens)) {
//                            //更新缓存中推荐人的token信息
//                            LoginToken loginToken;
//                            LoginUser loginUserForReq;
//                            String userVip;
//                            String recommendId;
//                            for (UserVipBO userVipBO : userVipBOS) {
//                                userVip = userVipBO.getUserVipLevel();
//                                recommendId = userVipBO.getRecommendId();
//                                for (UserToken userToken : userTokens) {
//                                    if (recommendId.equals(userToken.getRecommendId())) {
//                                        loginToken = loginTokenService.getById(userToken.getTokenId());
//                                        if (null != loginToken) {
//                                            loginUserForReq = loginToken.getLoginUser();
//                                            if (null != loginUserForReq) {
//                                                loginUserForReq.setUserLevel(userVip);
//                                                //更新token里面用户的信息(修改昵称、头像、用户等级)
//                                                loginToken.setLoginUser(loginUserForReq);
//                                                //生成新的token
//                                                loginTokenService.add(loginToken);
//                                            }
//                                        }
//                                        break;
//                                    }
//                                }
//
//                            }
//
//                        }
//
//                    }
                    Integer entryMoneyFailureFlag = entryMoneyBOResult.getEntryMoneyFailureFlag();
                    if (null != entryMoneyFailureFlag && entryMoneyFailureFlag == 1) {
                        throw new BusinessException(ResultCode.ENTRY_MONEY_ERROR);
                    }
                    return entryMoneyBOResult;
                }

            }
            //同时解锁5000USDT入金通道享受3倍放大额度，即可获得15000USD账户额度
            if (entryMoneyChannelType == 3) {
                String entryOtherCoinType = entryMoneyBO.getEntryOtherCoinType();
                if (ServerConstants.XWC.equalsIgnoreCase(entryOtherCoinType)) {
                    //如果用户之前入过金，那么必须等到之前入金的USD释放完才能入金
                    AZPlanBalance azPlanBalance = azPlanStaticIncomeClient.getAZPlanBalanceByUserId(userId);
                    BigDecimal orePool = azPlanBalance.getOrePool();
                    if (orePool.compareTo(BigDecimal.ZERO) > 0) {
                        throw new BusinessException(ResultCode.USER_CANNOT_ENTRY_MONEY);
                    }
                    String xwcExchangeUSDRatio = xtMapper.getXTExchangeRate(ServerConstants.XWC_USDT).getExchangeRate();
                    //获取USD按照兑换比例兑换的XWC的价格
                    BigDecimal xwcExchangeUSDAmount = BigDecimal.ZERO;
                    if (StringUtil.isNotEmpty(xwcExchangeUSDRatio)) {
                        xwcExchangeUSDAmount = BigDecimalUtils.divide(ServerConstants.THREE_CHANNEL_USDT_LOWEST_AMOUNT, String.valueOf(xwcExchangeUSDRatio));
                    }
                    //校验用户针对某个币种划转的余额是否充足
                    checkUserBalance(userId, entryOtherCoinType, xwcExchangeUSDAmount);
                    entryMoneyBO.setXwcExchangeUSDAmount(xwcExchangeUSDAmount);
                    //入金
                    EntryMoneyBO entryMoneyBOResult = azPlanStaticIncomeClient.entryMoney(entryMoneyBO);
                    //更新推荐人的token中的VIP信息
//                    List<UserVipBO> userVipBOS = entryMoneyBOResult.getUserVipBOS();
//                    if (CollectionUtil.isNotEmpty(userVipBOS)) {
//                        List<UserToken> userTokens = userClient.getTokenList(userVipBOS);
//                        if (CollectionUtil.isNotEmpty(userTokens)) {
//                            //更新缓存中推荐人的token信息
//                            LoginToken loginToken;
//                            LoginUser loginUserForReq;
//                            String userVip;
//                            String recommendId;
//                            for (UserVipBO userVipBO : userVipBOS) {
//                                userVip = userVipBO.getUserVipLevel();
//                                recommendId = userVipBO.getRecommendId();
//                                for (UserToken userToken : userTokens) {
//                                    if (recommendId.equals(userToken.getRecommendId())) {
//                                        loginToken = loginTokenService.getById(userToken.getTokenId());
//                                        if (null != loginToken) {
//                                            loginUserForReq = loginToken.getLoginUser();
//                                            if (null != loginUserForReq) {
//                                                loginUserForReq.setUserLevel(userVip);
//                                                //更新token里面用户的信息(修改昵称、头像、用户等级)
//                                                loginToken.setLoginUser(loginUserForReq);
//                                                //生成新的token
//                                                loginTokenService.add(loginToken);
//                                            }
//                                        }
//                                        break;
//                                    }
//                                }
//
//                            }
//
//                        }
//
//                    }
                    Integer entryMoneyFailureFlag = entryMoneyBOResult.getEntryMoneyFailureFlag();
                    if (null != entryMoneyFailureFlag && entryMoneyFailureFlag == 1) {
                        throw new BusinessException(ResultCode.ENTRY_MONEY_ERROR);
                    }
                    return entryMoneyBOResult;
                }
            }
        } else {
            throw new BusinessException(ResultCode.USER_NOT_LOGGED_IN);
        }
        return null;
    }

    /**
     * 校验用户针对某个币种划转的余额是否充足
     *
     * @param userId               用户主键
     * @param entryOtherCoinType   币种类型
     * @param xwcExchangeUSDAmount 兑换的金额
     */
    private void checkUserBalance(String userId, String entryOtherCoinType, BigDecimal xwcExchangeUSDAmount) {
        //校验用户针对某个币种划转的余额是否充足
        MoneyTransferRecord moneyTransferRecord = azPlanStaticIncomeClient.getMoneyTransferByUserIdAndCoinType(userId, entryOtherCoinType, null, 1);
        //判断某一个用户针对某一个币种从钱包划转到AZ计划的总额是否足够用于入金且判断用户的AZ计划的钱包金额是否足够用于入金
        log.info("入金金额：{}, 资金划转的余额：{}，az钱包余额：{}", xwcExchangeUSDAmount, moneyTransferRecord.getAmount(), moneyTransferRecord.getXwcAZPlanBalance());
        //fixme 没有考虑兑换金额。AZ计划的钱包金额 = 资金划转的余额 + USDT兑换XWC金额
//        if (moneyTransferRecord.getAmount().compareTo(xwcExchangeUSDAmount) < 0 || moneyTransferRecord.getXwcAZPlanBalance().compareTo(xwcExchangeUSDAmount) < 0) {
        if (moneyTransferRecord.getXwcAZPlanBalance().compareTo(xwcExchangeUSDAmount) < 0) {
            throw new BusinessException(ResultCode.USER_BALANCE_ERROR);
        }
    }

    /**
     * 根据币种类型和用户主键获取币种信息
     *
     * @param userId             用户主键
     * @param coinType           币种类型
     * @param transferType       1表示从钱包划转到AZ计划   2表示从AZ计划划转到钱包
     * @param coinBalanceVersion 币种余额版本号
     * @return 资金划转业务对象
     */
    @Override
    public MoneyTransferBO skipMoneyTransfer(String userId, String coinType, Integer transferType, Integer coinBalanceVersion) throws Exception {
        log.info("userId：{},coinType：{},transferType：{},coinBalanceVersion：{}", userId, coinType, transferType, coinBalanceVersion);
        LoginUser loginUser = LoginTokenHelper.getLoginUserFromRequest();
        MoneyTransferBO moneyTransferBO = MoneyTransferBO.builder().build();
        if (null != loginUser && userId.equals(loginUser.getId())) {
            //从钱包划转到AZ计划
            UserCoinBalance userCoinBalance = userClient.getUserCoinBalance(userId, coinType, null);
            String address = userCoinBalance.getCoinAddress();
            if (StringUtil.isEmpty(address)) {
                address = httpManager.getCoinAddress(coinType);
                //更新用户的余额信息表
                UserCoinBalance coinBalance = UserCoinBalance.builder().userId(userId).coinAddress(address)
                        .coinType(coinType).build();
                coinBalance.setUpdateTime(new Date());
                //确保用户余额表，一个币种地址对应一个用户主键，这样才能通过用户主键修改余额表
                userClient.updateUserCoinAddress(coinBalance);
            }
            if (transferType == 1) {
                //通过用户主键、币种地址、币种类型获取已经同步的充值总金额
                BigDecimal totalRechargeAmount = userClient.getTotalRechargeAmount(userId, coinType, address);
                if (null == totalRechargeAmount) {
                    totalRechargeAmount = BigDecimal.ZERO;
                }
                //获取已确认的充值交易
                List<DepositTran> depositTranList = httpManager.getDepositTranList(coinType, address, 3);
                BigDecimal balance = BigDecimal.ZERO;
                int depositTranSize = depositTranList.size();
                List<RechargeTranRecord> rechargeTranRecordList = Lists.newArrayListWithCapacity(depositTranSize);
                if (CollectionUtil.isNotEmpty(depositTranList)) {
                    RechargeTranRecord rechargeTranRecord;
                    for (DepositTran depositTran : depositTranList) {
                        balance = BigDecimalUtils.add(balance, String.valueOf(depositTran.getAmount()));
                        rechargeTranRecord = new RechargeTranRecord();
                        rechargeTranRecord.setId(SnowFlakeIdUtil.defaultId());
                        rechargeTranRecord.setUserId(userId);
                        rechargeTranRecord.setCoinType(coinType);
                        rechargeTranRecord.setCoinAddress(address);
                        rechargeTranRecord.setCoinAmount(depositTran.getAmount());
                        rechargeTranRecord.setTxId(depositTran.getTxid());
                        rechargeTranRecord.setTxTime(depositTran.getTxTime());
                        rechargeTranRecord.setCreateTime(depositTran.getCreatedAt());
                        rechargeTranRecord.setConfirmations(depositTran.getConfirmations());
                        rechargeTranRecord.setRechargeType(2);
                        rechargeTranRecordList.add(rechargeTranRecord);
                    }
                }
                //修改用户钱包余额表中的余额并插入某一个地址已经同步的充值记录，这个充值记录用于修改用户的币种余额
                BigDecimal remainBalance = BigDecimalUtils.subtract(String.valueOf(balance), String.valueOf(totalRechargeAmount));
                if (balance.compareTo(totalRechargeAmount) > 0) {
                    userCoinBalance.setUserId(userId);
                    userCoinBalance.setCoinBalance(remainBalance);
                    userCoinBalance.setVersion(coinBalanceVersion);
                    userCoinBalance.setUpdateTime(new Date());
                    if (CollectionUtil.isNotEmpty(rechargeTranRecordList)) {
                        userCoinBalance.setRechargeTranRecordList(rechargeTranRecordList);
                    }
                    userClient.addCoinBalance(userCoinBalance);
//                    if (count > 0) {
//                        coinBalanceVersion = 1 + coinBalanceVersion;
//                    }
                }
                //获取资金划转的版本号
                MoneyTransferRecord moneyTransferRecord = azPlanStaticIncomeClient.getMoneyTransferByUserIdAndCoinType(userId, coinType, address, transferType);
                log.info("从钱包划转到AZ计划的资金划转的版本号：{}", moneyTransferRecord.getVersion());
                moneyTransferBO = MoneyTransferBO.builder().coinBalance(setScale(moneyTransferRecord.getCoinBalance(), null))
                        .xwcCoinBalanceVersion(moneyTransferRecord.getXwcCoinBalanceVersion()).azPlanMoneyTransferVersion(moneyTransferRecord.getVersion())
                        .xwcAZPlanWalletVersion(moneyTransferRecord.getXwcAZPlanWalletVersion()).build();
            }
            //从AZ计划划转到钱包
            if (transferType == 2) {
                //获取资金划转的版本号
                MoneyTransferRecord moneyTransferRecord = azPlanStaticIncomeClient.getMoneyTransferByUserIdAndCoinType(userId, coinType, null, transferType);
                log.info("从AZ计划划转到钱包的资金划转的版本号：{}", moneyTransferRecord.getVersion());
                moneyTransferBO = MoneyTransferBO.builder().xwcAZPlanBalance(setScale(moneyTransferRecord.getXwcAZPlanBalance(), null))
                        .btcAZPlanBalance(setScale(moneyTransferRecord.getBtcAZPlanBalance(), null))
                        .xwcCoinBalanceVersion(moneyTransferRecord.getXwcCoinBalanceVersion()).btcCoinBalanceVersion(moneyTransferRecord.getBtcCoinBalanceVersion())
                        .azPlanMoneyTransferVersion(moneyTransferRecord.getVersion())
                        .xwcAZPlanWalletVersion(moneyTransferRecord.getXwcAZPlanWalletVersion())
                        .btcAZPlanWalletVersion(moneyTransferRecord.getBtcAZPlanWalletVersion()).build();
            }
            log.info("skip-money-transfer response：{}", moneyTransferBO.toString());
            return moneyTransferBO;
        } else {
            throw new BusinessException(ResultCode.USER_NOT_LOGGED_IN);
        }
    }

    /**
     * 点击首页的资产跳转到资产页面获取用户总的AZ计划获取的USD金额，包括用户的静态收益和动态收益的总和，相关用户的相关币种，比如XWC（用户钱包的XWC金额）和BTC（兑换的BTC金额）
     *
     * @param userId 用户主键
     * @return 相关用户的资产信息
     */
    @Override
    public Map<String, Object> skipAsset(String userId) {
        LoginUser loginUser = LoginTokenHelper.getLoginUserFromRequest();
        if (null != loginUser && userId.equals(loginUser.getId())) {
            Map<String, Object> map = Maps.newHashMapWithExpectedSize(1 << 3);
            //获取某一个用户的总收益（静态收益与动态收益之和减去兑换的总金额）
            BigDecimal totalIncomeAmount = azPlanStaticIncomeClient.getTotalIncomeAmount(userId);
            if (null == totalIncomeAmount) {
                totalIncomeAmount = BigDecimal.ZERO;
            }
            map.put("totalIncomeAmount", setScale(totalIncomeAmount, null));
            BigDecimal totalXWCAmount = azPlanStaticIncomeClient.getTotalXWCAmount(userId);
            if (null == totalXWCAmount) {
                totalXWCAmount = BigDecimal.ZERO;
            }
            BigDecimal totalUSDAmountForXWC = BigDecimal.ZERO;
            String xwcExchangeRatio = xtMapper.getXTExchangeRate(ServerConstants.XWC_USDT).getExchangeRate();
            if (StringUtil.isNotEmpty(xwcExchangeRatio)) {
                totalUSDAmountForXWC = BigDecimalUtils.multiply(xwcExchangeRatio, String.valueOf(totalXWCAmount));
            }
            map.put("totalXWCAmount", setScale(totalXWCAmount, null));
            map.put("totalUSDAmountForXWC", setScale(totalUSDAmountForXWC, null));
            BigDecimal totalBTCAmount = azPlanStaticIncomeClient.getTotalBTCAmount(userId);
            if (null == totalBTCAmount) {
                totalBTCAmount = BigDecimal.ZERO;
            }
            String btcExchangeRatio = xtMapper.getXTExchangeRate(ServerConstants.BTC_USDT).getExchangeRate();
            BigDecimal totalUSDAmountForBTC = BigDecimal.ZERO;
            if (StringUtil.isNotEmpty(btcExchangeRatio)) {
                totalUSDAmountForBTC = BigDecimalUtils.multiply(btcExchangeRatio, String.valueOf(totalBTCAmount));
            }
            map.put("totalBTCAmount", setScale(totalBTCAmount, null));
            map.put("totalUSDAmountForBTC", setScale(totalUSDAmountForBTC, null));
            BigDecimal totalUSDAmount = BigDecimalUtils.add(String.valueOf(totalIncomeAmount), String.valueOf(totalUSDAmountForXWC)).add(totalUSDAmountForBTC);
            map.put("totalUSDAmount", setScale(totalUSDAmount, ServerConstants.USDT_USD_SCALE));
            String xwcExchangeUSDRatio = xtMapper.getXTExchangeRate(ServerConstants.XWC_USDT).getExchangeRate();
            map.put("xwcExchangeUSDRatio", xwcExchangeUSDRatio);
            String btcExchangeUSDRatio = xtMapper.getXTExchangeRate(ServerConstants.BTC_USDT).getExchangeRate();
            map.put("btcExchangeUSDRatio", btcExchangeUSDRatio);
            //获取用户的AZ钱包版本号
            AZPlanWallet xwcAZPlanWallet = azPlanStaticIncomeClient.getAZPlanWallet(userId, ServerConstants.XWC);
            map.put("xwcAZPlanWalletVersion", xwcAZPlanWallet.getVersion());
            AZPlanWallet btcAZPlanWallet = azPlanStaticIncomeClient.getAZPlanWallet(userId, ServerConstants.BTC);
            map.put("btcAZPlanWalletVersion", btcAZPlanWallet.getVersion());
            //获取用于余额版本号
            UserCoinBalance userCoinBalance = userClient.getUserCoinBalance(userId, ServerConstants.XWC, null);
            map.put("userCoinBalanceVersion", userCoinBalance.getVersion());
            //获取资金划转的版本号
            MoneyTransferRecord moneyTransferRecord = azPlanStaticIncomeClient.getMoneyTransferByUserIdAndCoinType(userId, ServerConstants.XWC, null, 1);
            map.put("moneyTransferVersion", moneyTransferRecord.getVersion());
            //获取当前被推荐人的推荐人的矿池版本号、usdt钱包版本号
            List<UserRelativeVersionBO> userRelativeVersionBOList = azPlanStaticIncomeClient.getUserRelativeVersionBOList(userId);
            map.put("recommenderRelativeVersionBOList", userRelativeVersionBOList);
            //获取所有用户的矿池版本号
            map.put("userOrePoolVersionList", azPlanStaticIncomeClient.getUserOrePoolVersionList());
            return map;
        } else {
            throw new BusinessException(ResultCode.USER_NOT_LOGGED_IN);
        }
    }

    /**
     * 获取某一个用户矿池的大小
     *
     * @param userId   用户主键
     * @param coinType 币种类型
     * @return 矿池的大小和币种余额版本号
     */
    @Override
    public Map<String, Object> getOrePool(String userId, String coinType) {
        LoginUser loginUser = LoginTokenHelper.getLoginUserFromRequest();
        if (null != loginUser && userId.equals(loginUser.getId())) {
            return azPlanStaticIncomeClient.getOrePool(userId, coinType);
        } else {
            throw new BusinessException(ResultCode.USER_NOT_LOGGED_IN);
        }
    }

    /**
     * 兑换
     *
     * @param exchangeFlow 兑换流水实体
     * @return 兑换流水实体
     */
    @Override
    public ExchangeFlow exchange(ExchangeFlow exchangeFlow) {
        //获取当前总的收益
        String userId = exchangeFlow.getUserId();
        LoginUser loginUser = LoginTokenHelper.getLoginUserFromRequest();
        if (null != loginUser && userId.equals(loginUser.getId())) {
            //验证交易密码是否正确
            LoginCredential loginCredentialForDB = loginCredentialClient.getUserLoginCredential(userId);
            String tranPwd = exchangeFlow.getTranPwd();
            if (null != loginCredentialForDB) {
                String tranPwdForDB = loginCredentialForDB.getTranPwd();
                String salt = loginCredentialForDB.getRandomSalt();
                tranPwd = PasswordHelper.encodeBySalt(tranPwd, salt);
                if (StringUtil.isEmpty(tranPwdForDB) || !tranPwd.equals(tranPwdForDB)) {
                    throw new BusinessException(ResultCode.USER_TRAN_PWD_ERROR);
                }
            } else {
                throw new BusinessException(ResultCode.USER_LOGIN_CRE_IS_NOT_NULL);
            }
            //获取总收益（动态收益与静态收益之和减去兑换的usd数量）
            BigDecimal exchangeAmount = exchangeFlow.getExchangeAmount();
            if (exchangeAmount.compareTo(BigDecimal.ZERO) <= 0) {
                throw new BusinessException(ResultCode.EXCHANGE_AMOUNT_ERROR);
            }
            BigDecimal totalRemainIncomeAmount = azPlanStaticIncomeClient.getTotalIncomeAmount(userId);
            String coinTypeAfter = exchangeFlow.getCoinTypeAfter();
            if (ServerConstants.XWC.equalsIgnoreCase(coinTypeAfter)) {
                String xwcExchangeRatio = xtMapper.getXTExchangeRate(ServerConstants.XWC_USDT).getExchangeRate();
                if (StringUtil.isEmpty(xwcExchangeRatio)) {
                    xwcExchangeRatio = "0";
                }
                BigDecimal xwcExchangeUSDAmount = BigDecimalUtils.multiply(xwcExchangeRatio, String.valueOf(exchangeAmount));
                if (null == totalRemainIncomeAmount || totalRemainIncomeAmount.compareTo(xwcExchangeUSDAmount) < 0) {
                    throw new BusinessException(ResultCode.USER_TOTAL_INCOME_NOT_ENOUGH);
                }
                exchangeFlow.setUsdAmount(xwcExchangeUSDAmount);
            }
            if (ServerConstants.BTC.equalsIgnoreCase(coinTypeAfter)) {
                String btcExchangeRatio = xtMapper.getXTExchangeRate(ServerConstants.BTC_USDT).getExchangeRate();
                if (StringUtil.isEmpty(btcExchangeRatio)) {
                    btcExchangeRatio = "0";
                }
                BigDecimal btcExchangeUSDAmount = BigDecimalUtils.multiply(btcExchangeRatio, String.valueOf(exchangeAmount));
                if (null == totalRemainIncomeAmount || totalRemainIncomeAmount.compareTo(btcExchangeUSDAmount) < 0) {
                    throw new BusinessException(ResultCode.USER_TOTAL_INCOME_NOT_ENOUGH);
                }
                exchangeFlow.setUsdAmount(btcExchangeUSDAmount);
            }
            //插入兑换流水并增加用户的AZ计划钱包的余额
            return azPlanStaticIncomeClient.insertExchangeFlow(exchangeFlow);

        } else {
            throw new BusinessException(ResultCode.USER_NOT_LOGGED_IN);
        }
    }

    /**
     * 通过用户主键获取收益
     *
     * @param userId   用户主键
     * @param page     当前页码
     * @param pageSize 每页的大小
     * @return 收益流水
     */
    @Override
    public Map<String, Object> getIncomes(String userId, Integer page, Integer pageSize) throws Exception {
        LoginUser loginUser = LoginTokenHelper.getLoginUserFromRequest();
        if (null != loginUser && userId.equals(loginUser.getId())) {
            return azPlanStaticIncomeClient.getIncomes(userId, page, pageSize);
        } else {
            throw new BusinessException(ResultCode.USER_NOT_LOGGED_IN);
        }
    }

    /**
     * 获取USD账单(包括收益和兑换)
     *
     * @param userId   用户主键
     * @param coinType 币种类型
     * @param page     当前页码
     * @param pageSize 每页的大小
     * @return USD账单(包括收益和兑换)
     */
    @Override
    public Map<String, Object> getUsdBills(String userId, String coinType, Integer page, Integer pageSize) {
        LoginUser loginUser = LoginTokenHelper.getLoginUserFromRequest();
        if (null != loginUser && userId.equals(loginUser.getId())) {
            return azPlanStaticIncomeClient.getUsdBills(userId, coinType, page, pageSize);
        } else {
            throw new BusinessException(ResultCode.USER_NOT_LOGGED_IN);
        }
    }

    /**
     * 根据用户主键获取XWC、BTC、USDT的从AZ计划划转到钱包的总数量
     *
     * @param userId 用户主键
     * @return 钱包相关的总资产信息
     */
    @Override
    public Map<String, Object> getWalletTotalAssets(String userId) {
        LoginUser loginUser = LoginTokenHelper.getLoginUserFromRequest();
        if (null != loginUser && loginUser.getId().equals(userId)) {
            Map<String, Object> resultMap = Maps.newHashMapWithExpectedSize(1 << 4);
            //获取用户未审核的提币（冻结的）
            BigDecimal frozenAmountForXWC = azPlanStaticIncomeClient.getFrozenAmount(userId, ServerConstants.XWC);
            if (null == frozenAmountForXWC) {
                frozenAmountForXWC = BigDecimal.ZERO;
            }
            resultMap.put("frozenAmountForXWC", setScale(frozenAmountForXWC, null));
            BigDecimal totalAmountForXWC = azPlanStaticIncomeClient.getTotalWalletAmount(userId, ServerConstants.XWC);
            BigDecimal totalUSDAmountForXWC = BigDecimal.ZERO;
            if (null != totalAmountForXWC) {
                BigDecimal totalAmountForXWCAndFrozen = BigDecimalUtils.add(totalAmountForXWC, String.valueOf(frozenAmountForXWC));
                resultMap.put("totalAmountForXWC", setScale(totalAmountForXWCAndFrozen, null));
                resultMap.put("usableAmountForXWC", setScale(totalAmountForXWC, null));
                String xwcExchangeRatio = xtMapper.getXTExchangeRate(ServerConstants.XWC_USDT).getExchangeRate();
                if (StringUtil.isNotEmpty(xwcExchangeRatio)) {
                    totalUSDAmountForXWC = BigDecimalUtils.multiply(xwcExchangeRatio, String.valueOf(totalAmountForXWCAndFrozen));
                }
            } else {
                resultMap.put("totalAmountForXWC", setScale(BigDecimal.ZERO, null));
                resultMap.put("usableAmountForXWC", setScale(BigDecimal.ZERO, null));
            }
            resultMap.put("totalUSDAmountForXWC", setScale(totalUSDAmountForXWC, null));
            //获取从AZ计划划转到钱包的BTC的划转总金额
            BigDecimal frozenAmountForBTC = azPlanStaticIncomeClient.getFrozenAmount(userId, ServerConstants.BTC);
            if (null == frozenAmountForBTC) {
                frozenAmountForBTC = BigDecimal.ZERO;
            }
            resultMap.put("frozenAmountForBTC", setScale(frozenAmountForBTC, null));
            BigDecimal totalAmountForBTC = azPlanStaticIncomeClient.getTotalWalletAmount(userId, ServerConstants.BTC);
            BigDecimal totalUSDAmountForBTC = BigDecimal.ZERO;
            if (null != totalAmountForBTC) {
                BigDecimal totalAmountForBTCAndFrozen = BigDecimalUtils.add(totalAmountForBTC, String.valueOf(frozenAmountForBTC));
                resultMap.put("totalAmountForBTC", setScale(totalAmountForBTCAndFrozen, null));
                resultMap.put("usableAmountForBTC", setScale(totalAmountForBTC, null));
                String btcExchangeRatio = xtMapper.getXTExchangeRate(ServerConstants.BTC_USDT).getExchangeRate();
                if (StringUtil.isNotEmpty(btcExchangeRatio)) {
                    totalUSDAmountForBTC = BigDecimalUtils.multiply(btcExchangeRatio, String.valueOf(totalAmountForBTCAndFrozen));
                }
            } else {
                resultMap.put("totalAmountForBTC", setScale(BigDecimal.ZERO, null));
                resultMap.put("usableAmountForBTC", setScale(BigDecimal.ZERO, null));
            }
            resultMap.put("totalUSDAmountForBTC", setScale(totalUSDAmountForBTC, null));
            //获取从AZ计划划转到钱包的USDT的划转总金额
            BigDecimal frozenAmountForUSDT = azPlanStaticIncomeClient.getFrozenAmount(userId, ServerConstants.USDT);
            if (null == frozenAmountForUSDT) {
                frozenAmountForUSDT = BigDecimal.ZERO;
            }
            resultMap.put("frozenAmountForUSDT", setScale(frozenAmountForUSDT, null));
            BigDecimal totalAmountForUSDT = azPlanStaticIncomeClient.getTotalWalletAmount(userId, ServerConstants.USDT);
            BigDecimal totalUSDAmountForUSDT = BigDecimal.ZERO;
            if (null != totalAmountForUSDT) {
                BigDecimal totalAmountForUSDTAndFrozen = BigDecimalUtils.add(totalAmountForUSDT, String.valueOf(frozenAmountForUSDT));
                resultMap.put("totalAmountForUSDT", setScale(totalAmountForUSDTAndFrozen, null));
                resultMap.put("usableAmountForUSDT", setScale(totalAmountForUSDT, null));
                totalUSDAmountForUSDT = BigDecimalUtils.multiply(EXCHANGE_USDT_RATIO, String.valueOf(totalAmountForUSDTAndFrozen));
            } else {
                resultMap.put("totalAmountForUSDT", setScale(BigDecimal.ZERO, null));
                resultMap.put("usableAmountForUSDT", setScale(BigDecimal.ZERO, null));
            }
            resultMap.put("totalUSDAmountForUSDT", setScale(totalUSDAmountForUSDT, null));
            BigDecimal totalUSDAmount = BigDecimalUtils.add(String.valueOf(totalUSDAmountForXWC), String.valueOf(totalUSDAmountForBTC)).add(totalUSDAmountForUSDT);
            resultMap.put("totalUSDAmount", setScale(totalUSDAmount, ServerConstants.USDT_USD_SCALE));
            MoneyTransferRecord moneyTransferRecord = azPlanStaticIncomeClient.getMoneyTransferByUserIdAndCoinType(userId, null, null, 2);
            resultMap.put("xwcCoinBalanceVersion", moneyTransferRecord.getXwcCoinBalanceVersion());
            resultMap.put("btcCoinBalanceVersion", moneyTransferRecord.getBtcCoinBalanceVersion());
            resultMap.put("usdtCoinBalanceVersion", moneyTransferRecord.getUsdtCoinBalanceVersion());
            return resultMap;
        } else {
            throw new BusinessException(ResultCode.USER_NOT_LOGGED_IN);
        }
    }

    /**
     * 获取相关钱包中的币种账单
     *
     * @param userId      用户主键
     * @param coinType    币种类型
     * @param coinAddress 币种地址
     * @param page        当前页
     * @param pageSize    每页的大小
     * @return 钱包账单
     */
    @Override
    public List<WalletBillBO> getWalletBills(String userId, String coinType, String coinAddress, Integer page, Integer pageSize) {
        LoginUser loginUser = LoginTokenHelper.getLoginUserFromRequest();
        if (null != loginUser && userId.equals(loginUser.getId())) {
            //针对XWC获取充值流水、转入流水、转出流水、站内转出流水、站内转入流水、提币流水
            if (ServerConstants.XWC.equalsIgnoreCase(coinType)) {
                RechargeTranBO rechargeTranBO = RechargeTranBO.builder().coinType(ServerConstants.XWC).userId(userId).build();
                List<RechargeTran> depositTranList = azPlanStaticIncomeClient.getDepositList(rechargeTranBO).getRechargeTranList();
                int depositTranSize = depositTranList.size();
                //获取某一个币种的订单主键
                List<WithdrawOrder> withdrawOrderList = azPlanStaticIncomeClient.getWithdrawOrderList(userId, ServerConstants.XWC);
                List<WithdrawTran> withdrawTranList = Lists.newArrayListWithExpectedSize(withdrawOrderList.size());
                WithdrawTran withdrawTranForManager;
                List<WithdrawTran> withdrawTranTranForManager;
                if (CollectionUtil.isNotEmpty(withdrawOrderList)) {
                    for (WithdrawOrder withdrawOrder : withdrawOrderList) {
                        withdrawTranTranForManager = httpManager.getWithDrawTranList(ServerConstants.XWC, withdrawOrder.getId());
                        //已审核成功的提币订单
                        if (CollectionUtil.isNotEmpty(withdrawTranTranForManager)) {
                            withdrawTranForManager = withdrawTranTranForManager.get(0);
                            //只要同步到数字货币管理平台就表明审核成功
                            withdrawTranForManager.setState(3);
                            withdrawTranList.add(withdrawTranForManager);
                        } else {
                            //未审核、未审核成功的提币订单
                            withdrawTranForManager = new WithdrawTran();
                            withdrawTranForManager.setCreatedAt(withdrawOrder.getCreateTime());
                            withdrawTranForManager.setAmount(withdrawOrder.getAmount());
                            if (null != withdrawOrder.getCheckState() && withdrawOrder.getCheckState() == 3) {
                                withdrawTranForManager.setState(4);
                            } else {
                                withdrawTranForManager.setState(1);
                            }
                            withdrawTranList.add(withdrawTranForManager);
                        }
                    }
                }
                int withdrawTranSize = withdrawTranList.size();
                List<TransferInOutFlow> transferInOutFlowList = azPlanStaticIncomeClient.getTransferInOutFlowList(userId, ServerConstants.XWC, null);
                int transferInOutFlowSize = transferInOutFlowList.size();
                List<WalletBillBO> walletBills = Lists.newArrayListWithCapacity(depositTranSize + withdrawTranSize + transferInOutFlowSize);
                WalletBillBO walletBillBO;
                if (CollectionUtil.isNotEmpty(depositTranList)) {
                    for (RechargeTran depositTran : depositTranList) {
                        walletBillBO = new WalletBillBO();
                        walletBillBO.setCreateTime(depositTran.getCreateTime());
                        walletBillBO.setAmount(setScale(depositTran.getCoinAmount(), null));
                        walletBillBO.setTranStatus(3);
                        walletBillBO.setCategory(1);
                        walletBills.add(walletBillBO);
                    }
                }
                if (CollectionUtil.isNotEmpty(withdrawTranList)) {
                    for (WithdrawTran withdrawTran : withdrawTranList) {
                        walletBillBO = new WalletBillBO();
                        walletBillBO.setCreateTime(withdrawTran.getCreatedAt());
                        walletBillBO.setAmount(setScale(withdrawTran.getAmount(), null));
                        walletBillBO.setTranStatus(withdrawTran.getState());
                        walletBillBO.setCategory(2);
                        walletBills.add(walletBillBO);
                    }
                }
                if (CollectionUtil.isNotEmpty(transferInOutFlowList)) {
                    int flowType;
                    int status;
                    for (TransferInOutFlow transferInOutFlow : transferInOutFlowList) {
                        walletBillBO = new WalletBillBO();
                        walletBillBO.setCreateTime(transferInOutFlow.getCreateTime());
                        walletBillBO.setAmount(setScale(transferInOutFlow.getAmount(), null));
                        status = transferInOutFlow.getStatus();
                        if (status == 1) {
                            walletBillBO.setTranStatus(3);
                        }
                        flowType = transferInOutFlow.getFlowType();
                        if (flowType == 1) {
                            walletBillBO.setCategory(3);
                        }
                        if (flowType == 2) {
                            walletBillBO.setCategory(4);
                        }
                        if (flowType == 3) {
                            walletBillBO.setCategory(5);
                        }
                        if (flowType == 4) {
                            walletBillBO.setCategory(6);
                        }
                        walletBills.add(walletBillBO);
                    }
                }
                if (CollectionUtil.isNotEmpty(walletBills)) {
                    if (null != page && null != pageSize) {
                        //按照创建时间降序排列并分页
                        List<WalletBillBO> walletBillListPages = walletBills.stream().sorted(Comparator.comparing(WalletBillBO::getCreateTime)
                                .reversed()).skip(pageSize * (page - 1)).limit(pageSize).collect(Collectors.toList());
                        return walletBillListPages;
                    } else {
                        List<WalletBillBO> walletBillList = walletBills.stream().sorted(Comparator.comparing(WalletBillBO::getCreateTime)
                                .reversed()).collect(Collectors.toList());
                        return walletBillList;
                    }
                } else {
                    return walletBills;
                }

            }
            //针对BTC获取转入流水、提币流水
            if (ServerConstants.BTC.equals(coinType)) {
                List<WithdrawOrder> withdrawOrderList = azPlanStaticIncomeClient.getWithdrawOrderList(userId, ServerConstants.BTC);
                List<WithdrawTran> withdrawTranList = Lists.newArrayListWithExpectedSize(withdrawOrderList.size());
                WithdrawTran withdrawTranForManager;
                List<WithdrawTran> withdrawTranTranForManager;
                if (CollectionUtil.isNotEmpty(withdrawOrderList)) {
                    for (WithdrawOrder withdrawOrder : withdrawOrderList) {
                        withdrawTranTranForManager = httpManager.getWithDrawTranList(ServerConstants.BTC, withdrawOrder.getId());
                        if (CollectionUtil.isNotEmpty(withdrawTranTranForManager)) {
                            withdrawTranForManager = withdrawTranTranForManager.get(0);
                            //只要同步到数字货币管理平台就表明审核成功
                            withdrawTranForManager.setState(3);
                            withdrawTranList.add(withdrawTranForManager);
                        } else {
                            //未审核、未审核成功的提币订单
                            withdrawTranForManager = new WithdrawTran();
                            withdrawTranForManager.setCreatedAt(withdrawOrder.getCreateTime());
                            withdrawTranForManager.setAmount(withdrawOrder.getAmount());
                            if (null != withdrawOrder.getCheckState() && withdrawOrder.getCheckState() == 3) {
                                withdrawTranForManager.setState(4);
                            } else {
                                withdrawTranForManager.setState(1);
                            }
                            withdrawTranList.add(withdrawTranForManager);
                        }
                    }
                }
                int withdrawTranSize = withdrawTranList.size();
                List<TransferInOutFlow> transferInOutFlowList = azPlanStaticIncomeClient.getTransferInOutFlowList(userId, ServerConstants.BTC, null);
                int transferInOutFlowSize = transferInOutFlowList.size();
                List<WalletBillBO> walletBills = Lists.newArrayListWithCapacity(withdrawTranSize + transferInOutFlowSize);
                WalletBillBO walletBillBO;
                if (CollectionUtil.isNotEmpty(withdrawTranList)) {
                    for (WithdrawTran withdrawTran : withdrawTranList) {
                        walletBillBO = new WalletBillBO();
                        walletBillBO.setCreateTime(withdrawTran.getCreatedAt());
                        walletBillBO.setAmount(setScale(withdrawTran.getAmount(), null));
                        walletBillBO.setTranStatus(withdrawTran.getState());
                        walletBillBO.setCategory(2);
                        walletBills.add(walletBillBO);
                    }
                }
                if (CollectionUtil.isNotEmpty(transferInOutFlowList)) {
                    int status;
                    int flowType;
                    for (TransferInOutFlow transferInOutFlow : transferInOutFlowList) {
                        walletBillBO = new WalletBillBO();
                        walletBillBO.setCreateTime(transferInOutFlow.getCreateTime());
                        walletBillBO.setAmount(setScale(transferInOutFlow.getAmount(), null));
                        status = transferInOutFlow.getStatus();
                        if (status == 1) {
                            walletBillBO.setTranStatus(3);
                        }
                        flowType = transferInOutFlow.getFlowType();
                        if (flowType == 1) {
                            walletBillBO.setCategory(3);
                        }
                        if (flowType == 3) {
                            walletBillBO.setCategory(5);
                        }
                        if (flowType == 4) {
                            walletBillBO.setCategory(6);
                        }
                        walletBills.add(walletBillBO);
                    }
                }
                if (CollectionUtil.isNotEmpty(walletBills)) {
                    if (null != page && null != pageSize) {
                        //按照创建时间降序排列并分页
                        List<WalletBillBO> walletBillListPages = walletBills.stream().sorted(Comparator.comparing(WalletBillBO::getCreateTime)
                                .reversed()).skip(pageSize * (page - 1)).limit(pageSize).collect(Collectors.toList());
                        return walletBillListPages;
                    } else {
                        List<WalletBillBO> walletBillList = walletBills.stream().sorted(Comparator.comparing(WalletBillBO::getCreateTime)
                                .reversed()).collect(Collectors.toList());
                        return walletBillList;
                    }
                } else {
                    return walletBills;
                }

            }
            //针对USDT获取提币流水和转入流水
            if (ServerConstants.USDT.equals(coinType)) {
                List<WithdrawOrder> withdrawOrderList = azPlanStaticIncomeClient.getWithdrawOrderList(userId, ServerConstants.USDT);
                List<WithdrawTran> withdrawTranList = Lists.newArrayListWithExpectedSize(withdrawOrderList.size());
                WithdrawTran withdrawTranForManager;
                List<WithdrawTran> withdrawTranTranForManager;
                if (CollectionUtil.isNotEmpty(withdrawOrderList)) {
                    for (WithdrawOrder withdrawOrder : withdrawOrderList) {
                        withdrawTranTranForManager = httpManager.getWithDrawTranList(ServerConstants.USDT, withdrawOrder.getId());
                        if (CollectionUtil.isNotEmpty(withdrawTranTranForManager)) {
                            withdrawTranForManager = withdrawTranTranForManager.get(0);
                            //只要同步到数字货币管理平台就表明审核成功
                            withdrawTranForManager.setState(3);
                            withdrawTranList.add(withdrawTranForManager);
                        } else {
                            //未审核、未审核成功的提币订单
                            withdrawTranForManager = new WithdrawTran();
                            withdrawTranForManager.setCreatedAt(withdrawOrder.getCreateTime());
                            withdrawTranForManager.setAmount(withdrawOrder.getAmount());
                            if (null != withdrawOrder.getCheckState() && withdrawOrder.getCheckState() == 3) {
                                withdrawTranForManager.setState(4);
                            } else {
                                withdrawTranForManager.setState(1);
                            }
                            withdrawTranList.add(withdrawTranForManager);
                        }
                    }
                }
                int withdrawTranSize = withdrawTranList.size();
                List<TransferInOutFlow> transferInOutFlowList = azPlanStaticIncomeClient.getTransferInOutFlowList(userId, ServerConstants.USDT, null);
                int transferInOutFlowSize = transferInOutFlowList.size();
                List<WalletBillBO> walletBills = Lists.newArrayListWithCapacity(withdrawTranSize + transferInOutFlowSize);
                WalletBillBO walletBillBO;
                if (CollectionUtil.isNotEmpty(withdrawTranList)) {
                    for (WithdrawTran withdrawTran : withdrawTranList) {
                        walletBillBO = new WalletBillBO();
                        walletBillBO.setCreateTime(withdrawTran.getCreatedAt());
                        walletBillBO.setAmount(setScale(withdrawTran.getAmount(), null));
                        walletBillBO.setTranStatus(withdrawTran.getState());
                        walletBillBO.setCategory(2);
                        walletBills.add(walletBillBO);
                    }
                }
                if (CollectionUtil.isNotEmpty(transferInOutFlowList)) {
                    int status;
                    int flowType;
                    for (TransferInOutFlow transferInOutFlow : transferInOutFlowList) {
                        walletBillBO = new WalletBillBO();
                        walletBillBO.setCreateTime(transferInOutFlow.getCreateTime());
                        walletBillBO.setAmount(setScale(transferInOutFlow.getAmount(), null));
                        status = transferInOutFlow.getStatus();
                        if (status == 1) {
                            walletBillBO.setTranStatus(3);
                        }
                        flowType = transferInOutFlow.getFlowType();
                        if (flowType == 1) {
                            walletBillBO.setCategory(3);
                        }
                        if (flowType == 3) {
                            walletBillBO.setCategory(5);
                        }
                        if (flowType == 4) {
                            walletBillBO.setCategory(6);
                        }
                        walletBills.add(walletBillBO);
                    }
                }
                if (CollectionUtil.isNotEmpty(walletBills)) {
                    if (null != page && null != pageSize) {
                        //按照创建时间降序排列并分页
                        List<WalletBillBO> walletBillListPages = walletBills.stream().sorted(Comparator.comparing(WalletBillBO::getCreateTime)
                                .reversed()).skip(pageSize * (page - 1)).limit(pageSize).collect(Collectors.toList());
                        return walletBillListPages;
                    } else {
                        List<WalletBillBO> walletBillList = walletBills.stream().sorted(Comparator.comparing(WalletBillBO::getCreateTime)
                                .reversed()).collect(Collectors.toList());
                        return walletBillList;
                    }
                } else {
                    return walletBills;
                }

            }
            return null;
        } else {
            throw new BusinessException(ResultCode.USER_NOT_LOGGED_IN);
        }
    }

    /**
     * 获取所有用户的入金流水和提币流水
     *
     * @param coinType 币种类型
     * @return 所有用户的入金流水和提币流水
     */
    @Override
    public List<WalletAllBillBO> getWalletAllBills(String coinType) {
        List<WithdrawOrder> withdrawOrderList = azPlanStaticIncomeClient.getWithdrawOrderList(null, coinType);
        List<WithdrawTran> withdrawTranList = Lists.newArrayListWithExpectedSize(withdrawOrderList.size());
        WithdrawTran withdrawTranForManager;
        List<WithdrawTran> withdrawTranTranForManager;
        if (CollectionUtil.isNotEmpty(withdrawOrderList)) {
            for (WithdrawOrder withdrawOrder : withdrawOrderList) {
                withdrawTranTranForManager = httpManager.getWithDrawTranList(withdrawOrder.getCoinType(), withdrawOrder.getId());
                if (CollectionUtil.isNotEmpty(withdrawTranTranForManager)) {
                    withdrawTranForManager = withdrawTranTranForManager.get(0);
                    withdrawTranForManager.setPhone(withdrawOrder.getPhone());
                    withdrawTranForManager.setCoinType(withdrawOrder.getCoinType());
                    withdrawTranList.add(withdrawTranForManager);
                }
            }
        }
        int withdrawTranSize = withdrawTranList.size();
        //获取入金流水
        List<EntryMoneyFlow> entryMoneyFlowList = azPlanStaticIncomeClient.getEntryMoneyFlowList();
        int entryMoneyFlowSize = entryMoneyFlowList.size();
        List<WalletAllBillBO> walletAllBills = Lists.newArrayListWithCapacity(withdrawTranSize + entryMoneyFlowSize);
        WalletAllBillBO walletAllBillBO;
        if (CollectionUtil.isNotEmpty(withdrawTranList)) {
            for (WithdrawTran withdrawTran : withdrawTranList) {
                walletAllBillBO = new WalletAllBillBO();
                walletAllBillBO.setCreateTime(withdrawTran.getCreatedAt());
                walletAllBillBO.setAmount(setScale(withdrawTran.getAmount(), null));
                walletAllBillBO.setTranStatus(withdrawTran.getState());
                walletAllBillBO.setCategory(1);
                walletAllBillBO.setCoinType(withdrawTran.getCoinType());
                walletAllBillBO.setUserPhone(withdrawTran.getPhone());
                walletAllBills.add(walletAllBillBO);
            }
        }
        if (CollectionUtil.isNotEmpty(entryMoneyFlowList)) {
            for (EntryMoneyFlow entryMoneyFlow : entryMoneyFlowList) {
                walletAllBillBO = new WalletAllBillBO();
                walletAllBillBO.setCreateTime(entryMoneyFlow.getCreateTime());
                walletAllBillBO.setAmount(setScale(entryMoneyFlow.getEntryAmount(), null));
                walletAllBillBO.setTranStatus(3);
                walletAllBillBO.setCategory(2);
                walletAllBillBO.setCoinType(entryMoneyFlow.getCoinTypeBefore());
                walletAllBillBO.setUserPhone(entryMoneyFlow.getPhone());
                walletAllBills.add(walletAllBillBO);
            }
        }
        if (CollectionUtil.isNotEmpty(walletAllBills)) {
            return walletAllBills.stream().sorted(Comparator.comparing(WalletAllBillBO::getCreateTime)
                    .reversed()).collect(Collectors.toList());
        }
        return walletAllBills;
    }

    /**
     * 跳转到提币页面
     *
     * @param userId    用户主键
     * @param coinType  币种类型
     * @param toAddress 提币目的地址
     * @return 提币业务对象
     */
    @Override
    public WithdrawBO skipWithdraw(String userId, String coinType, String toAddress) {
        LoginUser loginUser = LoginTokenHelper.getLoginUserFromRequest();
        if (null != loginUser && userId.equals(loginUser.getId())) {
            //返回相关的币种实际钱包余额版本号
            UserCoinBalance userCoinBalance = userClient.getUserCoinBalance(userId, coinType, toAddress);
            WithdrawBO withdrawBO = WithdrawBO.builder().build();
            if (ServerConstants.XWC.equalsIgnoreCase(coinType)) {
                withdrawBO.setXwcCoinBalanceVersion(userCoinBalance.getVersion());
                withdrawBO.setXwcCoinBalance(userCoinBalance.getCoinBalance());
            }
            if (ServerConstants.BTC.equalsIgnoreCase(coinType)) {
                withdrawBO.setBtcCoinBalanceVersion(userCoinBalance.getVersion());
                withdrawBO.setBtcCoinBalance(userCoinBalance.getCoinBalance());
            }
            if (ServerConstants.USDT.equalsIgnoreCase(coinType)) {
                withdrawBO.setUsdtCoinBalanceVersion(userCoinBalance.getVersion());
                withdrawBO.setUsdtCoinBalance(userCoinBalance.getCoinBalance());
            }
            log.info("userId:{},选择的币种:{},针对的币种地址:{},跳转到提币页面返回的响应:{}", userId, coinType, toAddress, withdrawBO.toString());
            return withdrawBO;
        } else {
            throw new BusinessException(ResultCode.USER_NOT_LOGGED_IN);
        }
    }

    /**
     * 提币
     *
     * @param withdrawOrder 提币订单PO对象
     * @return 提币订单PO对象
     */
    @Override
    public void withdraw(WithdrawOrder withdrawOrder) {
        String userId = withdrawOrder.getUserId();
        LoginUser loginUser = LoginTokenHelper.getLoginUserFromRequest();
        if (null != loginUser && userId.equals(loginUser.getId())) {
            UserOperateAuth userOperateAuth = userClient.getUserOperateAuthByUserIdAndOperateCode(userId, ServerConstants.WITHDRAW_CODE);
            if (null != userOperateAuth && 1 == userOperateAuth.getOperateState()) {
                throw new BusinessException(ResultCode.PERMISSION_NO_ACCESS);
            }
            String phone = withdrawOrder.getPhone();
            // 校验手机号
            if (!ValidatorUtil.isMobile(phone)) {
                throw new BusinessException(ResultCode.USER_PHONE_FORMAT_ERROR);
            }
            //系统主账户不支持充提
            if (loginUser.getPhone().equals(defaultUserPhone)) {
                throw new BusinessException(ResultCode.DEFAULT_USER_FUNCTION_LIMIT);
            }
            LoginUserCredential loginUserCredential = userClient.getUserByPhone(phone);
            if (null == loginUserCredential) {
                throw new BusinessException(ResultCode.USER_IS_NOT_EXIST);
            }
            //判断用户是否已经实名认证
            UserCertification userCertification = userClient.getUserCertificationByUserId(userId);
            if (null == userCertification) {
                throw new BusinessException(ResultCode.USER_IS_NOT_AUTH);
            }
            String userLevel = loginUserCredential.getUserLevel();
            if (ServerConstants.ZERO_LEVEL.equals(userLevel) && userCertification.getBaseAuthState() != 2) {
                throw new BusinessException(ResultCode.USER_IS_NOT_AUTH);
            }
            if ((ServerConstants.ONE_LEVEL.equals(userLevel) || ServerConstants.TWO_LEVEL.equals(userLevel) || ServerConstants.THREE_LEVEL.equals(userLevel)) && userCertification.getHighAuthState() != 2) {
                throw new BusinessException(ResultCode.USER_IS_NOT_AUTH);
            }
            //获取区号
            String areaNo = loginUserCredential.getAreaNo();
            String newPhone = UserServiceImpl.areaNoJoinPhone(phone, areaNo);
            //验证验证码
            String authCode = String.valueOf(redisHandler.get(CacheKeyEnum.SMS_WITHDRAW_AUTH_CODE.formatKey(newPhone)));
            log.info("手机号：【{}】，对应的验证码：【{}】", newPhone, authCode);
            String authCodeClient = withdrawOrder.getAuthCode();
            if (StringUtil.isEmpty(authCode) || !authCode.equals(authCodeClient)) {
                throw new BusinessException(ResultCode.AUTH_CODE_ERROR);
            }
            //验证交易密码
            String tranPwd = withdrawOrder.getTranPwd();
            String tranPwdForDB = loginUserCredential.getTranPwd();
            String salt = loginUserCredential.getRandomSalt();
            tranPwd = PasswordHelper.encodeBySalt(tranPwd, salt);
            if (StringUtil.isEmpty(tranPwdForDB) || !tranPwd.equals(tranPwdForDB)) {
                throw new BusinessException(ResultCode.USER_TRAN_PWD_ERROR);
            }
            //校验币种地址
            String coinType = withdrawOrder.getCoinType();
            String toAddress = withdrawOrder.getToAddr();
            Boolean verifyCoinAddress = httpManager.verifyCoinAddress(coinType, toAddress);
            if (!verifyCoinAddress) {
                throw new BusinessException(ResultCode.VERIFY_COIN_ADDRESS_FAILURE);
            }
            BigDecimal amount = withdrawOrder.getAmount();
            if (null == amount) {
                amount = BigDecimal.ZERO;
            }
            BigDecimal fee = BigDecimal.ZERO;
            BigDecimal feeClient = withdrawOrder.getFee();
            if (ServerConstants.XWC.equalsIgnoreCase(coinType)) {
                if (amount.compareTo(xwcMinWithdrawAmount) < 0) {
                    throw new BusinessException(ResultCode.WITHDRAW_IS_TOO_LOW);
                }
//                fee = BigDecimalUtils.multiply(String.valueOf(xwcMinWithdrawFeeRatio), String.valueOf(amount));
                //如果5%小于20个XWC则按20XWC收取
                fee = new BigDecimal("20");
//                if (fee.compareTo(twentyFee) < 0) {
//                    fee = twentyFee;
//                }
                if (fee.compareTo(feeClient) != 0) {
                    throw new BusinessException(ResultCode.WITHDRAW_FEE_ERROR);
                }
            }
            if (ServerConstants.BTC.equalsIgnoreCase(coinType)) {
                if (amount.compareTo(btcMinWithdrawAmount) < 0) {
                    throw new BusinessException(ResultCode.WITHDRAW_IS_TOO_LOW);
                }
                fee = BigDecimalUtils.multiply(String.valueOf(btcMinWithdrawFeeRatio), String.valueOf(amount));
                BigDecimal btcFee = new BigDecimal("0.0025");
                if (fee.compareTo(btcFee) < 0) {
                    fee = btcFee;
                }
                if (fee.compareTo(feeClient) != 0) {
                    throw new BusinessException(ResultCode.WITHDRAW_FEE_ERROR);
                }
            }
            if (ServerConstants.USDT.equalsIgnoreCase(coinType)) {
                if (amount.compareTo(usdtMinWithdrawAmount) < 0) {
                    throw new BusinessException(ResultCode.WITHDRAW_IS_TOO_LOW);
                }
//                fee = BigDecimalUtils.multiply(String.valueOf(usdtMinWithdrawFeeRatio), String.valueOf(amount));
                fee = new BigDecimal("5");
//                if (fee.compareTo(usdtFee) < 0) {
//                    fee = usdtFee;
//                }
                if (fee.compareTo(feeClient) != 0) {
                    throw new BusinessException(ResultCode.WITHDRAW_FEE_ERROR);
                }
            }
            log.info("提币金额：{}，手续费：{}", amount, fee);
            //判断用户用于提币的钱包余额是否足以用来进行提币
            UserCoinBalance userCoinBalance = userClient.getUserCoinBalance(userId, coinType, null);
            BigDecimal coinBalance = userCoinBalance.getCoinBalance();
            if (null == coinBalance) {
                coinBalance = BigDecimal.ZERO;
            }
            if (coinBalance.compareTo(BigDecimal.ZERO) <= 0 || coinBalance.compareTo(amount) < 0) {
                throw new BusinessException(ResultCode.USER_BALANCE_ERROR);
            }
            BigDecimal amountAddFee = BigDecimalUtils.add(amount, String.valueOf(fee));
            //如果手续费与提币的金额之和小于用户余额，则到账数量为提币的金额
            if (amountAddFee.compareTo(coinBalance) < 0) {
                withdrawOrder.setAmount(amount);
            } else {
                //如果手续费与提币的金额之和大于或等于用户余额，则到账数量为用户的余额减去手续费
                BigDecimal amountSubFee = BigDecimalUtils.subtract(String.valueOf(coinBalance), String.valueOf(fee));
                withdrawOrder.setAmount(amountSubFee);
            }
            withdrawOrder.setFee(fee);
            withdrawOrder.setId(SnowFlakeIdUtil.defaultId());
            azPlanStaticIncomeClient.withdraw(withdrawOrder);
        } else {
            throw new BusinessException(ResultCode.USER_NOT_LOGGED_IN);
        }
    }

    /**
     * 转账
     *
     * @param inSiteUserBO 转账业务对象
     * @return 影响的行数
     */
    @Override
    public int inSiteTransfer(InSiteUserBO inSiteUserBO) {
        String transferOutUserId = inSiteUserBO.getTransferOutUserId();
        LoginUser loginUser = LoginTokenHelper.getLoginUserFromRequest();
        if (null != loginUser && loginUser.getId().equals(transferOutUserId)) {
            UserOperateAuth userOperateAuth = userClient.getUserOperateAuthByUserIdAndOperateCode(transferOutUserId, ServerConstants.INSITE_TRANSFER_IN_CODE);
            if (null != userOperateAuth && 1 == userOperateAuth.getOperateState()) {
                throw new BusinessException(ResultCode.PERMISSION_NO_ACCESS);
            }
            String phone = userClient.getById(transferOutUserId).getPhone();
            // 校验手机号
            if (!ValidatorUtil.isMobile(phone)) {
                throw new BusinessException(ResultCode.USER_PHONE_FORMAT_ERROR);
            }
            //系统主账户不支持充提
            if (loginUser.getPhone().equals(defaultUserPhone)) {
                throw new BusinessException(ResultCode.DEFAULT_USER_FUNCTION_LIMIT);
            }
            LoginUserCredential loginUserCredential = userClient.getUserByPhone(phone);
            if (null == loginUserCredential) {
                throw new BusinessException(ResultCode.USER_IS_NOT_EXIST);
            }
            //获取区号
            String areaNo = loginUserCredential.getAreaNo();
            String newPhone = UserServiceImpl.areaNoJoinPhone(phone, areaNo);
            //验证验证码
            String authCode = String.valueOf(redisHandler.get(CacheKeyEnum.SMS_IN_SITE_TRANSFER_AUTH_CODE.formatKey(newPhone)));
            log.info("手机号：【{}】，对应的验证码：【{}】", newPhone, authCode);
            String authCodeClient = inSiteUserBO.getAuthCode();
            if (StringUtil.isEmpty(authCode) || !authCode.equals(authCodeClient)) {
                throw new BusinessException(ResultCode.AUTH_CODE_ERROR);
            }
            //验证交易密码
            String tranPwd = inSiteUserBO.getTranPwd();
            String tranPwdForDB = loginUserCredential.getTranPwd();
            String salt = loginUserCredential.getRandomSalt();
            tranPwd = PasswordHelper.encodeBySalt(tranPwd, salt);
            if (StringUtil.isEmpty(tranPwdForDB) || !tranPwd.equals(tranPwdForDB)) {
                throw new BusinessException(ResultCode.USER_TRAN_PWD_ERROR);
            }
            //转账双方是否进行了基础认证
            String transferInUserId = inSiteUserBO.getTransferInUserId();
            if (StringUtil.isEmpty(transferInUserId)) {
                log.info("转入方用户主键不能为空！");
                throw new BusinessException(ResultCode.USER_IS_NOT_EXIST);
            } else {
                User transferInUser = userClient.getById(transferInUserId);
                if (null == transferInUser) {
                    log.info("转入方用户不存在！");
                    throw new BusinessException(ResultCode.USER_IS_NOT_EXIST);
                }
            }
//            UserCertification transferInUserCertification = userClient.getUserCertificationByUserId(transferInUserId);
//            if (null == transferInUserCertification || 2 != transferInUserCertification.getBaseAuthState()) {
//                throw new BusinessException(ResultCode.USER_IS_NOT_AUTH);
//            }
//            UserCertification transferOutUserCertification = userClient.getUserCertificationByUserId(transferOutUserId);
//            if (null == transferOutUserCertification || 2 != transferOutUserCertification.getBaseAuthState()) {
//                throw new BusinessException(ResultCode.USER_IS_NOT_AUTH);
//            }
            //自己不能够给自己转账
            if (transferOutUserId.equals(transferInUserId)) {
                throw new BusinessException(ResultCode.OWN_INNER_TRANSFER_IN_ERROR);
            }
            BigDecimal amount = inSiteUserBO.getTransferAmount();
            if (null == amount) {
                amount = BigDecimal.ZERO;
            }
            String coinType = inSiteUserBO.getCoinType();
            BigDecimal fee = BigDecimal.ZERO;
            if (ServerConstants.XWC.equalsIgnoreCase(coinType)) {
                if (amount.compareTo(xwcMinWithdrawAmount) < 0) {
                    throw new BusinessException(ResultCode.WITHDRAW_IS_TOO_LOW);
                }
                fee = new BigDecimal("30");
            }
            if (ServerConstants.BTC.equalsIgnoreCase(coinType)) {
                if (amount.compareTo(btcMinWithdrawAmount) < 0) {
                    throw new BusinessException(ResultCode.WITHDRAW_IS_TOO_LOW);
                }
                fee = BigDecimalUtils.multiply(String.valueOf(btcMinWithdrawFeeRatio), String.valueOf(amount));
                BigDecimal btcFee = new BigDecimal("0.0025");
                if (fee.compareTo(btcFee) < 0) {
                    fee = btcFee;
                }
            }
            if (ServerConstants.USDT.equalsIgnoreCase(coinType)) {
                if (amount.compareTo(usdtMinWithdrawAmount) < 0) {
                    throw new BusinessException(ResultCode.WITHDRAW_IS_TOO_LOW);
                }
                fee = new BigDecimal("8");
            }
//            BigDecimal fee = inSiteUserBO.getFee();
//            if (null == fee) {
//                fee = BigDecimal.ZERO;
//            }
            inSiteUserBO.setFee(fee);
            log.info("站内转账金额：{}，站内转账的手续费：{}", amount, fee);
            amount = BigDecimalUtils.add(fee, String.valueOf(amount));
            UserCoinBalance userCoinBalance = userClient.getUserCoinBalance(transferOutUserId, coinType, null);
            BigDecimal coinBalance = userCoinBalance.getCoinBalance();
            if (null == coinBalance) {
                coinBalance = BigDecimal.ZERO;
            }
            if (coinBalance.compareTo(BigDecimal.ZERO) <= 0 || coinBalance.compareTo(amount) < 0) {
                throw new BusinessException(ResultCode.USER_BALANCE_ERROR);
            }
            return azPlanStaticIncomeClient.inSiteTransfer(inSiteUserBO);
        } else {
            throw new BusinessException(ResultCode.USER_NOT_LOGGED_IN);
        }
    }

    /**
     * 通过站内手机号获取转入方信息（包括转入方的钱包版本号）
     *
     * @param userPhone 用户手机号
     * @return 转入方信息
     */
    @Override
    public InSiteUserBO getInSiteUserInfo(String userPhone) {
        LoginUserCredential loginUserCredential = userClient.getUserByPhone(userPhone);
        if (null == loginUserCredential) {
            throw new BusinessException(ResultCode.USER_IS_NOT_EXIST);
        }
        InSiteUserBO inSiteUserBO = InSiteUserBO.builder().userAccount(loginUserCredential.getAccount()).userNickName(loginUserCredential.getNickname())
                .userPhone(userPhone).transferInUserId(loginUserCredential.getId()).build();
        UserCertification userCertification = userClient.getUserCertificationByUserId(loginUserCredential.getId());
        if (null != userCertification) {
            inSiteUserBO.setUserName(userCertification.getName());
        }
        UserCoinBalance userXwcCoinBalance = userClient.getUserCoinBalance(loginUserCredential.getId(), ServerConstants.XWC, null);
        if (null != userXwcCoinBalance) {
            inSiteUserBO.setTransferInXwcCoinBalanceVersion(userXwcCoinBalance.getVersion());
        }
        UserCoinBalance userBtcCoinBalance = userClient.getUserCoinBalance(loginUserCredential.getId(), ServerConstants.BTC, null);
        if (null != userBtcCoinBalance) {
            inSiteUserBO.setTransferInBtcCoinBalanceVersion(userBtcCoinBalance.getVersion());
        }
        UserCoinBalance userUsdtCoinBalance = userClient.getUserCoinBalance(loginUserCredential.getId(), ServerConstants.USDT, null);
        if (null != userUsdtCoinBalance) {
            inSiteUserBO.setTransferInUsdtCoinBalanceVersion(userUsdtCoinBalance.getVersion());
        }
        log.info("用户手机号:{},转入方的信息:{}", userPhone, inSiteUserBO.toString());
        return inSiteUserBO;
    }

    /**
     * 获取提币订单列表
     *
     * @return 提币订单列表
     */
    @Override
    public WithdrawBO getWithdrawList(WithdrawBO withdrawBO) {
        return azPlanStaticIncomeClient.getWithdrawList(withdrawBO);
    }

    /**
     * 审核提币订单
     *
     * @param withdrawOrder 提笔订单对象
     */
    @Override
    public int checkWithdraw(WithdrawOrder withdrawOrder) {
//        String userId = withdrawOrder.getUserId();
//        LoginUser loginUser = LoginTokenHelper.getLoginUserFromRequest();
//        if (null != loginUser && userId.equals(loginUser.getId())) {
        int count = 0;
        if (null != withdrawOrder && null != withdrawOrder.getCheckState()) {
            WithdrawOrder withdrawOrderDB = azPlanStaticIncomeClient.getWithdrawOrder(withdrawOrder.getId());
            if (null != withdrawOrderDB && withdrawOrderDB.getCheckState() == 2) {
                throw new BusinessException(ResultCode.WITHDRAW_IS_CHECKED);
            }
            //审核成功（提交提币任务到数字数据管理平台并扣减用户钱包金额）
            if (2 == withdrawOrder.getCheckState()) {
//                if (null == withdrawOrder.getAmount()) {
//                    withdrawOrder.setAmount(BigDecimal.ZERO);
//                }
//                if (null == withdrawOrder.getFee()) {
//                    withdrawOrder.setFee(BigDecimal.ZERO);
//                }
//                BigDecimal amount = BigDecimalUtils.add(withdrawOrder.getAmount(), String.valueOf(withdrawOrder.getFee()));
//                if (StringUtil.isNotEmpty(withdrawOrder.getUserId()) && StringUtil.isNotEmpty(withdrawOrder.getCoinType())) {
//                    UserCoinBalance userCoinBalanceDB = userClient.getUserCoinBalance(withdrawOrder.getUserId(), withdrawOrder.getCoinType(), null);
//                    if (null != userCoinBalanceDB) {
//                        BigDecimal coinBalance = userCoinBalanceDB.getCoinBalance();
//                        if (null == coinBalance || coinBalance.compareTo(BigDecimal.ZERO) <= 0 || coinBalance.compareTo(amount) < 0) {
//                            throw new BusinessException(ResultCode.USER_BALANCE_ERROR);
//                        }
//                    }
//                }
//                UserCoinBalance userCoinBalance = UserCoinBalance.builder().userId(withdrawOrder.getUserId()).coinType(withdrawOrder.getCoinType())
//                        .version(withdrawOrder.getUserCoinBalanceVersion()).coinBalance(amount).withdrawOrderId(withdrawOrder.getId()).build();
                if (null != withdrawOrderDB) {
                    count = azPlanStaticIncomeClient.updateWithdrawOrder(withdrawOrder);
                }
//                int count = userClient.reduceUserCoinBalance(userCoinBalance);
                if (count > 0) {
                    log.info("审核通过，提交提币任务");
                    //向数字货币管理平台发送提币任务
                    httpManager.sendWithdrawTask(withdrawOrder);
                }
            } else {
                if (null != withdrawOrderDB) {
                    count = azPlanStaticIncomeClient.updateWithdrawOrder(withdrawOrder);
                }
            }
        }
        return count;
//        } else {
//            throw new BusinessException(ResultCode.USER_NOT_LOGGED_IN);
//        }
    }

    /**
     * 更新XT交易所的兑换比例
     */
    @Override
    @Transactional(transactionManager = ServerConstants.TRANSACTION_MANAGER, rollbackFor = Exception.class)
    public void updateXTExchangeRate() {
        log.info("更新XT交易所的兑换比例开始");
        long begin = System.currentTimeMillis();
        String xwcExchangeRatio = exchangeHouseManager.getTwentyFourHoursMarket(ServerConstants.XWC_USDT);
        String btcExchangeRatio = exchangeHouseManager.getTwentyFourHoursMarket(ServerConstants.BTC_USDT);
        //更新XWC兑换USDT的兑换比例
        XTExchangeRate xwcUsdtExchangeRate = xtMapper.getXTExchangeRate(ServerConstants.XWC_USDT);
        XTExchangeRate btcUsdtExchangeRate = xtMapper.getXTExchangeRate(ServerConstants.BTC_USDT);
        List<XTExchangeRate> xtExchangeRateAddList = Lists.newArrayList();
        List<XTExchangeRate> xtExchangeRateUpdateList = Lists.newArrayList();
        if (StringUtil.isNotEmpty(xwcExchangeRatio)) {
            if (null != xwcUsdtExchangeRate) {
                //不为空就是更新
                xwcUsdtExchangeRate.setUpdateTime(new Date());
                xwcUsdtExchangeRate.setExchangeRate(xwcExchangeRatio);
                xtExchangeRateUpdateList.add(xwcUsdtExchangeRate);
            } else {
                //为空就是插入
                xwcUsdtExchangeRate = XTExchangeRate.builder().exchangeType(ServerConstants.XWC_USDT)
                        .exchangeRate(xwcExchangeRatio).build();
                xwcUsdtExchangeRate.setUpdateTime(new Date());
                xwcUsdtExchangeRate.setCreateTime(new Date());
                xtExchangeRateAddList.add(xwcUsdtExchangeRate);
            }
        }

        if (StringUtil.isNotEmpty(btcExchangeRatio)) {
            if (null != btcUsdtExchangeRate) {
                //不为空就是更新
                btcUsdtExchangeRate.setUpdateTime(new Date());
                btcUsdtExchangeRate.setExchangeRate(btcExchangeRatio);
                xtExchangeRateUpdateList.add(btcUsdtExchangeRate);
            } else {
                //为空就是插入
                btcUsdtExchangeRate = XTExchangeRate.builder().exchangeType(ServerConstants.BTC_USDT)
                        .exchangeRate(btcExchangeRatio).build();
                btcUsdtExchangeRate.setUpdateTime(new Date());
                btcUsdtExchangeRate.setCreateTime(new Date());
                xtExchangeRateAddList.add(btcUsdtExchangeRate);
            }
        }
        if (CollectionUtil.isNotEmpty(xtExchangeRateAddList)) {
            xtMapper.insertXTExchangeRateList(xtExchangeRateAddList);
        }
        if (CollectionUtil.isNotEmpty(xtExchangeRateUpdateList)) {
            xtMapper.updateXTExchangeRateList(xtExchangeRateUpdateList);
        }
        log.info("执行更新XT交易所的兑换比例任务需要的时间：【{}】", System.currentTimeMillis() - begin);

    }

    /**
     * 手动打印内存树
     *
     * @return 内存树
     */
    @Override
    public String manualPrintMemoryTree(String userPhone) {
        LoginUserCredential loginUserCredential = userClient.getUserByPhone(userPhone);
        String userId = null != loginUserCredential ? loginUserCredential.getId() : null;
        return azPlanStaticIncomeClient.manualPrintMemoryTree(userId);
    }

    /**
     * 获取对应父账户下面的所有子账户累计入金金额
     */
    @Override
    public BigDecimal getAllChildAccountTotalEntryAmount(String userPhone) {
        LoginUserCredential loginUserCredential = userClient.getUserByPhone(userPhone);
        if (null != loginUserCredential) {
            String userId = loginUserCredential.getId();
            return azPlanStaticIncomeClient.getAllChildAccountTotalEntryAmount(userId);
        }
        return BigDecimal.ZERO;
    }

    /**
     * 获取所有子节点列表
     */
    @Override
    public Map<String, Object> getIndirectRecommendsByUserId(String parentId, Integer entryMoneyState, Integer page, Integer pageSize) {
        return azPlanStaticIncomeClient.getIndirectRecommends(parentId, entryMoneyState, page, pageSize);
    }

    /**
     * 获取所有子节点列表
     */
    @Override
    public Map<String, Object> getIndirectRecommendsByPhone(String phone, Integer entryMoneyState, Integer page, Integer pageSize) {
        LoginUserCredential user = userClient.getUserByPhone(phone);
        if (null != user) {
            return azPlanStaticIncomeClient.getIndirectRecommends(user.getId(), entryMoneyState, page, pageSize);
        } else {
            throw new BusinessException(ResultCode.USER_NOT_EXIST);
        }
    }

    /**
     * 获取充值记录列表
     *
     * @param rechargeTranBO
     * @return
     */
    @Override
    public RechargeTranBO getDepositList(RechargeTranBO rechargeTranBO) {
        return azPlanStaticIncomeClient.getDepositList(rechargeTranBO);
    }

    /**
     * 获取用户资产列表
     *
     * @param userAssetBO 用户资产业务对象
     * @return 用户资产列表
     */
    @Override
    public UserAssetBO getUserAssetList(UserAssetBO userAssetBO) {
        return azPlanStaticIncomeClient.getUserAssetList(userAssetBO);
    }

    /**
     * 标记内部用户
     *
     * @param phone 用户手机号
     */
    @Override
    public void markInnerUser(String phone) {
        LoginUserCredential loginUser = userClient.getUserByPhone(phone);
        if (loginUser != null) {
            String userId = loginUser.getId();
            azPlanStaticIncomeClient.markInnerUser(userId);
        } else {
            throw new BusinessException(ResultCode.USER_NOT_EXIST);
        }
    }

    /**
     * 获取入金列表
     *
     * @param entryMoneyFlowBO 用户入金流水业务对象
     * @return 用户入金列表
     */
    @Override
    public EntryMoneyFlowBO getEntryMoneyFlowList(EntryMoneyFlowBO entryMoneyFlowBO) {
        return azPlanStaticIncomeClient.getEntryMoneyFlowList(entryMoneyFlowBO);
    }

    /**
     * 获取兑换流水列表
     *
     * @param exchangeFlowBO 用户兑换流水业务对象
     * @return 用户兑换列表
     */
    @Override
    public ExchangeFlowBO getExchangeFlowList(ExchangeFlowBO exchangeFlowBO) {
        return azPlanStaticIncomeClient.getExchangeFlowList(exchangeFlowBO);
    }

    /**
     * 下载充值excel表单
     *
     * @param response 响应
     * @throws Exception 异常
     */
    @Override
    public void exportDepositExcel(HttpServletResponse response) throws Exception {
        log.info("导出excel开始");
        List<String> titles = Arrays.asList("用户ID", "用户账号", "币种", "充值时间", "充值地址", "数量", "确认次数", "充值类型", "备注");

        // 查数据写EXCEL
        List<List<String>> dataList = new ArrayList<>();
        RechargeTranBO rechargeTranBO = azPlanStaticIncomeClient.getDepositList(new RechargeTranBO());
        if (null != rechargeTranBO) {
            List<RechargeTran> rechargeTranList = rechargeTranBO.getRechargeTranList();
            if (CollectionUtil.isNotEmpty(rechargeTranList)) {
                rechargeTranList.forEach(rechargeTran -> dataList.add(Arrays.asList(
                        rechargeTran.getUserId(),
                        rechargeTran.getUserAccount(),
                        rechargeTran.getCoinType(),
                        new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(rechargeTran.getTxTime()),
                        rechargeTran.getCoinAddress(),
                        String.valueOf(rechargeTran.getCoinAmount()),
                        String.valueOf(rechargeTran.getConfirmations()),
                        1 == rechargeTran.getRechargeType() ? "内部转入" : 2 == rechargeTran.getRechargeType() ? "区块链转入" : 3 == rechargeTran.getRechargeType() ? "站内转入" : "内部转出",
                        rechargeTran.getRemark()
                )));
            }
        }
        ExcelUtil.export("DepositRecord", titles, dataList, response);

    }

    /**
     * 下载提币excel表单
     *
     * @param response 响应
     * @throws Exception 异常
     */
    @Override
    public void exportWithdrawExcel(HttpServletResponse response) throws Exception {
        log.info("导出excel开始");
        List<String> titles = Arrays.asList("用户ID", "用户账号", "币种", "提交时间", "提币地址", "数量", "手续费", "审核状态", "审核时间");

        List<List<String>> dataList = new ArrayList<>();
        WithdrawBO withdrawBO = azPlanStaticIncomeClient.getWithdrawList(new WithdrawBO());
        if (null != withdrawBO) {
            List<WithdrawOrder> withdrawOrderList = withdrawBO.getWithdrawOrderList();
            if (CollectionUtil.isNotEmpty(withdrawOrderList)) {
                withdrawOrderList.forEach(withdrawOrder -> {
                    dataList.add(Arrays.asList(
                            withdrawOrder.getUserId(),
                            withdrawOrder.getUserAccount(),
                            withdrawOrder.getCoinType(),
                            new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(withdrawOrder.getCreateTime()),
                            withdrawOrder.getToAddr(),
                            String.valueOf(withdrawOrder.getAmount()),
                            withdrawOrder.getFee().toPlainString(),
                            null == withdrawOrder.getCheckState() ? "" : 0 == withdrawOrder.getCheckState() ? "未审核" : 1 == withdrawOrder.getCheckState() ? "审核中"
                                    : 2 == withdrawOrder.getCheckState() ? "审核成功" : "审核失败",
                            null == withdrawOrder.getCheckState() || (1 == withdrawOrder.getCheckState() || 0 == withdrawOrder.getCheckState()) ? "" : new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(withdrawOrder.getCheckTime())
                    ));
                });
            }
        }
        ExcelUtil.export("WithdrawOrder", titles, dataList, response);
    }

    /**
     * 下载用户资金excel表单
     *
     * @param response 响应
     * @throws Exception 异常
     */
    @Override
    public void exportUserAssertExcel(HttpServletResponse response) throws Exception {
        log.info("导出excel开始");

        List<String> titles = Arrays.asList("用户ID", "用户账号", "钱包XWC余额", "钱包BTC余额", "钱包USD余额", "账户额度", "AZ XWC余额", "AZ BTC余额", "AZ USD余额", "内部用户");

        List<List<String>> dataList = new ArrayList<>();
        UserAssetBO userAssetBO = azPlanStaticIncomeClient.getUserAssetList(new UserAssetBO());
        if (null != userAssetBO) {
            List<UserAsset> userAssetList = userAssetBO.getUserAssetList();
            if (CollectionUtil.isNotEmpty(userAssetList)) {
                userAssetList.forEach(userAsset -> {
                    //totalDynamicIncome + totalStaticIncome - totalExchangeAmount
                    BigDecimal totalUsdBalance = userAsset.getTotalDynamicIncome().add(userAsset.getTotalStaticIncome()).subtract(BigDecimalUtils.defaultZero(userAsset.getTotalExchangeAmount()));
                    dataList.add(Arrays.asList(
                                    userAsset.getUserId(),
                                    userAsset.getUserAccount(),
                                    String.valueOf(userAsset.getXwcWalletBalance()),
                                    String.valueOf(userAsset.getBtcWalletBalance()),
                                    String.valueOf(userAsset.getUsdtWalletBalance()),
                                    String.valueOf(userAsset.getOrePool()),
                                    String.valueOf(userAsset.getXwcAzBalance()),
                                    String.valueOf(userAsset.getBtcAzBalance()),
                                    String.valueOf(totalUsdBalance),
                                    User.UserTypeEnum.INNER_USER.name().equals(userAsset.getUserType()) ? "是" : "否")
                    );
                });
            }
        }
        ExcelUtil.export("UserAssertRecord", titles, dataList, response);
    }

    /**
     * 下载入金流水excel表单
     *
     * @param response 响应
     * @throws Exception 异常
     */
    @Override
    public void exportEntryMoneyExcel(HttpServletResponse response) throws Exception {
        log.info("导出excel开始");

        List<String> titles = Arrays.asList("用户ID", "用户账号", "入金usdt", "等值xwc", "价格xwc/usdt", "矿池算力usd", "入金时间");

        List<List<String>> dataList = new ArrayList<>();
        EntryMoneyFlowBO entryMoneyFlowBO = azPlanStaticIncomeClient.getEntryMoneyFlowList(new EntryMoneyFlowBO());
        if (null != entryMoneyFlowBO) {
            List<EntryMoneyFlow> entryMoneyFlowList = entryMoneyFlowBO.getEntryMoneyFlowList();
            if (CollectionUtil.isNotEmpty(entryMoneyFlowList)) {
                entryMoneyFlowList.forEach(entryMoneyFlow -> dataList.add(Arrays.asList(
                                entryMoneyFlow.getUserId(),
                                entryMoneyFlow.getUserAccount(),
                                String.valueOf(entryMoneyFlow.getAmount()),
                                String.valueOf(entryMoneyFlow.getEntryAmount()),
                                entryMoneyFlow.getPrice(),
                                String.valueOf(entryMoneyFlow.getOrePool()),
                                new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(entryMoneyFlow.getEntryTime())
                        )
                ));
            }
        }
        ExcelUtil.export("EntryMoneyFlow", titles, dataList, response);
    }

    /**
     * 下载兑换流水excel表单
     *
     * @param response 响应
     * @throws Exception 异常
     */
    @Override
    public void exportExchangeExcel(HttpServletResponse response) throws Exception {
        log.info("导出excel开始");

        List<String> titles = Arrays.asList("用户ID", "用户账号", "兑换usd", "兑换", "价格", "兑换时间");

        List<List<String>> dataList = new ArrayList<>();
        ExchangeFlowBO exchangeFlowBO = azPlanStaticIncomeClient.getExchangeFlowList(new ExchangeFlowBO());
        if (null != exchangeFlowBO) {
            List<ExchangeFlow> exchangeFlowList = exchangeFlowBO.getExchangeFlowList();
            if (CollectionUtil.isNotEmpty(exchangeFlowList)) {
                exchangeFlowList.forEach(exchangeFlow -> dataList.add(Arrays.asList(
                                exchangeFlow.getUserId(),
                                exchangeFlow.getUserAccount(),
                                String.valueOf(exchangeFlow.getUsdAmount()),
                                exchangeFlow.getExchangeAmount() + exchangeFlow.getCoinTypeAfter(),
                                exchangeFlow.getPrice() + exchangeFlow.getCoinTypeAfter() + "/usd",
                                new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(exchangeFlow.getExchangeTime())
                        )
                ));
            }
        }
        ExcelUtil.export("ExchangeFlow", titles, dataList, response);
    }

    /**
     * 下载收益日报统计excel表单
     *
     * @param response 响应
     * @throws Exception 异常
     */
    @Override
    public void exportIncomeStatisticsExcel(HttpServletResponse response) throws Exception {
        log.info("导出excel开始");

        List<String> titles = Arrays.asList("收益时间", "POS挖矿奖励", "邀请奖励", "系统奖励");

        List<List<String>> dataList = new ArrayList<>();
        IncomeStatisticsDailyBO incomeStatisticsDailyBO = azPlanStaticIncomeClient.getIncomeStatisticsList(new IncomeStatisticsDailyBO());
        if (null != incomeStatisticsDailyBO) {
            List<IncomeStatisticsBO> incomeStatisticsList = incomeStatisticsDailyBO.getIncomeStatisticsList();
            if (CollectionUtil.isNotEmpty(incomeStatisticsList)) {
                incomeStatisticsList.forEach(incomeStatistics -> dataList.add(Arrays.asList(
                                new SimpleDateFormat("yyyy-MM-dd").format(incomeStatistics.getIncomeDate()),
                                String.valueOf(incomeStatistics.getPosMinerReward()),
                                String.valueOf(incomeStatistics.getInviteReward()),
                                String.valueOf(incomeStatistics.getSystemReward())
                        )
                ));
            }
        }
        ExcelUtil.export("IncomeStatisticsDaily", titles, dataList, response);
    }

    /**
     * 下载收益明细excel表单
     *
     * @param response 响应
     * @throws Exception 异常
     */
    @Override
    public void exportIncomeDetailExcel(HttpServletResponse response) throws Exception {
        log.info("导出excel开始");

        List<String> titles = Arrays.asList("用户账号", "类型", "数量", "时间");

        List<List<String>> dataList = new ArrayList<>();
        IncomeStatisticsDailyBO incomeStatisticsDailyBO = azPlanStaticIncomeClient.getIncomeDetailList(new IncomeStatisticsDailyBO());
        if (null != incomeStatisticsDailyBO) {
            List<IncomeFlow> incomeFlowList = incomeStatisticsDailyBO.getIncomeList();
            if (CollectionUtil.isNotEmpty(incomeFlowList)) {
                incomeFlowList.forEach(incomeFlow -> dataList.add(Arrays.asList(
                                incomeFlow.getUserAccount(),
                                1 == incomeFlow.getIncomeType() ? "POS挖矿奖励" : 2 == incomeFlow.getIncomeType() ? "邀请奖励" : "系统奖励",
                                String.valueOf(incomeFlow.getIncomeAmount()),
                                new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(incomeFlow.getIncomeDateTime())
                        )
                ));
            }
        }
        ExcelUtil.export("IncomeDetailDaily", titles, dataList, response);
    }


    /**
     * 添加公告
     *
     * @param azNotice 公告对象
     * @return 影响的行数
     */
    @Override
    public int addAzNotice(AzNotice azNotice) {
        LoginUser loginUser = LoginTokenHelper.getLoginUserFromRequest();
        azNotice.setUserId(loginUser.getId());
        return azPlanStaticIncomeClient.addAzNotice(azNotice);
    }

    /**
     * 修改公告
     *
     * @param azNotice 公告对象
     * @return 影响的行数
     */
    @Override
    public int updateAzNotice(AzNotice azNotice) {
        return azPlanStaticIncomeClient.updateAzNotice(azNotice);
    }

    /**
     * 根据公告主键查询单个公告
     *
     * @param id 主键
     * @return 公告对象
     */
    @Override
    public AzNotice getAzNoticeById(String id) {
        return azPlanStaticIncomeClient.getAzNoticeById(id);
    }

    /**
     * 根据相关的检索条件获取公告列表
     *
     * @param azNoticeBO 公告业务对象
     * @return 公告业务对象
     */
    @Override
    public AzNoticeBO getAzNoticeList(AzNoticeBO azNoticeBO) {
        //获取调用来源
        String callSource = RequestContextUtil.getRequest().getHeader(HeaderConstants.CALL_SOURCE);
        azNoticeBO.setCallSource(callSource);
        String language = azNoticeBO.getLanguage();
        if (StringUtil.isEmpty(language)) {
            language = ServerConstants.CN;
            azNoticeBO.setLanguage(language);
        }
        AzNoticeBO azNoticeBOAfter = azPlanStaticIncomeClient.getAzNoticeList(azNoticeBO);
        if (null != azNoticeBOAfter) {
            List<AzNotice> azNoticeList = azNoticeBOAfter.getAzNoticeList();
            if (CollectionUtil.isNotEmpty(azNoticeList)) {
                for (AzNotice azNotice : azNoticeList) {
                    if (ServerConstants.CN.equals(language)) {
                        azNotice.setEnglishNoticeTitle(null);
                        azNotice.setKrNoticeTitle(null);
                        azNotice.setJpNoticeTitle(null);
                        azNotice.setHkNoticeTitle(null);
                        azNotice.setRaNoticeTitle(null);
                        azNotice.setEnglishNoticeContent(null);
                        azNotice.setKrNoticeContent(null);
                        azNotice.setJpNoticeContent(null);
                        azNotice.setHkNoticeContent(null);
                        azNotice.setRaNoticeContent(null);
                    }
                    if (ServerConstants.ES.equals(language)) {
                        azNotice.setNoticeTitle(azNotice.getEnglishNoticeTitle());
                        azNotice.setEnglishNoticeTitle(null);
                        azNotice.setKrNoticeTitle(null);
                        azNotice.setJpNoticeTitle(null);
                        azNotice.setHkNoticeTitle(null);
                        azNotice.setRaNoticeTitle(null);
                        azNotice.setNoticeContent(azNotice.getEnglishNoticeContent());
                        azNotice.setEnglishNoticeContent(null);
                        azNotice.setKrNoticeContent(null);
                        azNotice.setJpNoticeContent(null);
                        azNotice.setHkNoticeContent(null);
                        azNotice.setRaNoticeContent(null);
                    }
                    if (ServerConstants.KR.equals(language)) {
                        azNotice.setNoticeTitle(azNotice.getKrNoticeTitle());
                        azNotice.setEnglishNoticeTitle(null);
                        azNotice.setKrNoticeTitle(null);
                        azNotice.setJpNoticeTitle(null);
                        azNotice.setHkNoticeTitle(null);
                        azNotice.setRaNoticeTitle(null);
                        azNotice.setNoticeContent(azNotice.getKrNoticeContent());
                        azNotice.setEnglishNoticeContent(null);
                        azNotice.setKrNoticeContent(null);
                        azNotice.setJpNoticeContent(null);
                        azNotice.setHkNoticeContent(null);
                        azNotice.setRaNoticeContent(null);
                    }
                    if (ServerConstants.JP.equals(language)) {
                        azNotice.setNoticeTitle(azNotice.getJpNoticeTitle());
                        azNotice.setEnglishNoticeTitle(null);
                        azNotice.setKrNoticeTitle(null);
                        azNotice.setJpNoticeTitle(null);
                        azNotice.setHkNoticeTitle(null);
                        azNotice.setRaNoticeTitle(null);
                        azNotice.setNoticeContent(azNotice.getJpNoticeContent());
                        azNotice.setEnglishNoticeContent(null);
                        azNotice.setKrNoticeContent(null);
                        azNotice.setJpNoticeContent(null);
                        azNotice.setHkNoticeContent(null);
                        azNotice.setRaNoticeContent(null);
                    }
                    if (ServerConstants.HK.equals(language)) {
                        azNotice.setNoticeTitle(azNotice.getHkNoticeTitle());
                        azNotice.setEnglishNoticeTitle(null);
                        azNotice.setKrNoticeTitle(null);
                        azNotice.setJpNoticeTitle(null);
                        azNotice.setHkNoticeTitle(null);
                        azNotice.setRaNoticeTitle(null);
                        azNotice.setNoticeContent(azNotice.getHkNoticeContent());
                        azNotice.setEnglishNoticeContent(null);
                        azNotice.setKrNoticeContent(null);
                        azNotice.setJpNoticeContent(null);
                        azNotice.setHkNoticeContent(null);
                        azNotice.setRaNoticeContent(null);
                    }
                    if (ServerConstants.RA.equals(language)) {
                        azNotice.setNoticeTitle(azNotice.getRaNoticeTitle());
                        azNotice.setEnglishNoticeTitle(null);
                        azNotice.setKrNoticeTitle(null);
                        azNotice.setJpNoticeTitle(null);
                        azNotice.setHkNoticeTitle(null);
                        azNotice.setRaNoticeTitle(null);
                        azNotice.setNoticeContent(azNotice.getRaNoticeContent());
                        azNotice.setEnglishNoticeContent(null);
                        azNotice.setKrNoticeContent(null);
                        azNotice.setJpNoticeContent(null);
                        azNotice.setHkNoticeContent(null);
                        azNotice.setRaNoticeContent(null);
                    }
                }
                azNoticeBOAfter.setAzNoticeList(azNoticeList);
            }
        }
        return azNoticeBOAfter;
    }

    /**
     * 修改公告的上线与下线状态
     *
     * @param azNotice 公告对象
     * @return 影响的行数
     */
    @Override
    public int upDownAzNotice(AzNotice azNotice) {
        return azPlanStaticIncomeClient.upDownAzNotice(azNotice);
    }

    /**
     * 获取收益统计日报列表
     *
     * @param incomeStatisticsDailyBO 收益统计日报业务对象
     * @return 收益统计日报列表
     */
    @Override
    public IncomeStatisticsDailyBO getIncomeStatisticsList(IncomeStatisticsDailyBO incomeStatisticsDailyBO) {
        return azPlanStaticIncomeClient.getIncomeStatisticsList(incomeStatisticsDailyBO);
    }

    /**
     * 获取收益明细列表
     *
     * @param incomeStatisticsDailyBO 收益统计日报业务对象
     * @return 收益明细列表
     */
    @Override
    public IncomeStatisticsDailyBO getIncomeDetailList(IncomeStatisticsDailyBO incomeStatisticsDailyBO) {
        return azPlanStaticIncomeClient.getIncomeDetailList(incomeStatisticsDailyBO);
    }

    /**
     * 获取快讯接口
     *
     * @return 快讯列表
     */
    public FastNewsResponseVo getFastNews() {
        try {
            return NEWS_LOCAL_CACHE.get("news", () -> {
                Map data = new LinkedHashMap();
                data.put("businessNo", "B100000");
                data.put("tag", "recommend");
                data.put("requestId", UUID.randomUUID());
                data.put("id", "");
                //获取sign
                String sign = SignatureUtil.signature(newsKey, JsonUtil.object2Json(data), "SHA-512", "UTF8");
                Map remoteData = new HashMap();
                remoteData.put("channel", newsChannel);
                remoteData.put("sign", sign);
                remoteData.put("data", data);
                RestTemplate restTemplate = new RestTemplate();
                HttpHeaders headers = new HttpHeaders();
                headers.setContentType(MediaType.APPLICATION_JSON);
                HttpEntity<Map> entity = new HttpEntity<>(remoteData, headers);
                HttpEntity<String> response = restTemplate.exchange(newsUrl, HttpMethod.POST, entity, String.class);
                return JsonUtil.json2Object(response.getBody(), FastNewsResponseVo.class);
            });
        } catch (ExecutionException e) {
            log.error("getFastNews error", e);
        }
        return null;
    }

    @Override
    public void manualExecSchedule() {
        azPlanStaticIncomeClient.generateStaticIncome();
    }

    /**
     * 保留小数位数
     *
     * @param amount 金额
     * @param scale  保留位数
     * @return 保留精度的小数
     */
    private String setScale(BigDecimal amount, Integer scale) {
        if (null != scale) {
            return BigDecimalUtils.keepDecimalPlaces(amount, scale).toPlainString();
        } else {
            return amount.toPlainString();
        }
    }

}
